Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCode Raguet <ignacio.code@gmail.com>2013-10-04 18:41:30 (GMT)
committer Code Raguet <ignacio.code@gmail.com>2013-10-04 18:41:30 (GMT)
commit970eab40fae16e4318cd97d7801ecb8b44857bf1 (patch)
tree595be1d5bdb1b10b3f35ee95c65a85afcf63ce6b
parentbe208a817cb6dc3ba08b9356b96d3298bb3bbc89 (diff)
parent5b21d357296cb0bd94619d1d5db588a12352e2da (diff)
Merge branch 'DEV'v4.22
-rw-r--r--webapp/polls/fixtures/closed_poll.json5
-rw-r--r--webapp/polls/fixtures/open_poll.json5
-rw-r--r--webapp/polls/fixtures/poll.json5
-rw-r--r--webapp/polls/models.py42
-rw-r--r--webapp/polls/tests/poll_result_file_tests.py126
-rw-r--r--webapp/polls/tests/poll_tests.py12
-rw-r--r--webapp/polls/views.py154
-rw-r--r--webapp/pollster/fixtures/generic_pollster.json22
-rw-r--r--webapp/pollster/fixtures/mongo_generic_pollster.json5
-rw-r--r--webapp/sociologist/poll_urls.py1
-rw-r--r--webapp/utils/test.py19
-rw-r--r--webapp/webapp/features/cannot_modify_poll_structure.feature6
-rw-r--r--webapp/webapp/features/fixtures/invalid.poll_result0
-rw-r--r--webapp/webapp/features/fixtures/not_asigned_poll.poll_result6
-rw-r--r--webapp/webapp/features/fixtures/other_owner.poll_result6
-rw-r--r--webapp/webapp/features/fixtures/same_time.poll_result19
-rw-r--r--webapp/webapp/features/fixtures/same_time_copy.poll_result19
-rw-r--r--webapp/webapp/features/fixtures/valid.poll_result6
-rw-r--r--webapp/webapp/features/fixtures/valid_copy.poll_result6
-rw-r--r--webapp/webapp/features/remove_poll_results_from_poll.py18
-rw-r--r--webapp/webapp/features/researcher_adds_images_to_options.py6
-rw-r--r--webapp/webapp/features/steps.py13
-rw-r--r--webapp/webapp/features/terrain.py36
-rw-r--r--webapp/webapp/features/upload_poll_result.feature68
-rw-r--r--webapp/webapp/features/upload_poll_result.py60
-rw-r--r--webapp/webapp/test_settings.py2
26 files changed, 516 insertions, 151 deletions
diff --git a/webapp/polls/fixtures/closed_poll.json b/webapp/polls/fixtures/closed_poll.json
new file mode 100644
index 0000000..f40c7e1
--- /dev/null
+++ b/webapp/polls/fixtures/closed_poll.json
@@ -0,0 +1,5 @@
+{
+ "_id": {"$oid": "51d471b8f966f43d509a969a"},
+ "status": "Cerrada",
+ "name": "closed_poll"
+}
diff --git a/webapp/polls/fixtures/open_poll.json b/webapp/polls/fixtures/open_poll.json
new file mode 100644
index 0000000..7da00a7
--- /dev/null
+++ b/webapp/polls/fixtures/open_poll.json
@@ -0,0 +1,5 @@
+{
+ "_id": {"$oid": "51d471b8f966f43d509a969c"},
+ "status": "Abierta",
+ "name": "open_poll"
+}
diff --git a/webapp/polls/fixtures/poll.json b/webapp/polls/fixtures/poll.json
new file mode 100644
index 0000000..5c78dc2
--- /dev/null
+++ b/webapp/polls/fixtures/poll.json
@@ -0,0 +1,5 @@
+{
+ "_id": {"$oid": "51d471b8f966f43d509a969b"},
+ "status": "Cerrada",
+ "name": "poll"
+}
diff --git a/webapp/polls/models.py b/webapp/polls/models.py
index 1117728..8320c00 100644
--- a/webapp/polls/models.py
+++ b/webapp/polls/models.py
@@ -10,6 +10,7 @@ import copy
import warnings
import glob
import errno
+import hashlib
from distutils.dir_util import copy_tree
from bson import ObjectId, DBRef
from datetime import datetime
@@ -442,7 +443,7 @@ class Poll(Document, AbstracErrorObject):
return ";".join(header)
- def get_resutls_path(self):
+ def get_results_path(self):
results_path = self._results_path
poll_id = self.id
if poll_id is None:
@@ -452,7 +453,7 @@ class Poll(Document, AbstracErrorObject):
def set_results_path(self, path):
self._results_path = path
- results_path = property(get_resutls_path, set_results_path)
+ results_path = property(get_results_path, set_results_path)
def get_result_files(self, as_instance_of=None):
result_file = PollResultFile if not as_instance_of else as_instance_of
@@ -1549,3 +1550,40 @@ class PollResultFile(object):
def delete(self):
file_path = self.file_path
os.remove(file_path)
+
+ @property
+ def hash(self):
+ data = self.get_data()
+ if 'upload_timestamp' in data.keys():
+ del data['upload_timestamp']
+ data_str = str(data)
+ hash_hexdigest = hashlib.md5(data_str).hexdigest()
+ return hash_hexdigest
+
+ def exists(self):
+ poll_id = self.data['poll_id']
+ poll = Poll.get(poll_id)
+ result_path = os.path.join(poll.results_path, self.get_file_name())
+ exists = os.path.exists(result_path)
+
+ if not exists:
+ results = poll.get_result_files()
+ hashes = [result.hash for result in results]
+ exists = self.hash in hashes
+
+ return exists
+
+ def is_authored_by(self, user):
+ """Check if result is authored by user."""
+ result_author = self.get_pollster_username()
+ username = user.username
+ return username == result_author
+
+ def poll_is_assigned_to(self, user):
+ poll_id = self.get_data()['poll_id']
+ pollster = user.pollster
+
+ assigned_polls_id = [
+ str(p.id) for p in Poll.assigned_to_pollster(pollster)]
+
+ return poll_id in assigned_polls_id
diff --git a/webapp/polls/tests/poll_result_file_tests.py b/webapp/polls/tests/poll_result_file_tests.py
index 996a8b9..36e0c87 100644
--- a/webapp/polls/tests/poll_result_file_tests.py
+++ b/webapp/polls/tests/poll_result_file_tests.py
@@ -1,13 +1,15 @@
-# pylint: disable=C0111,C0103
+# pylint: disable=C0111,C0103,C0321,R0904
import json
import tempfile
import os
+import hashlib
from django.test import TestCase
from django.conf import settings
+from mock import Mock, patch
from polls.models import PollResultFile, Poll
-from utils.test import MongoTestCase
+from utils.test import MongoTestCase, create_results_dir
def json_construc(data):
@@ -26,12 +28,18 @@ def make_temp_file(data):
class PollResultFileTest(MongoTestCase):
def setUp(self):
+ create_results_dir()
+
data = {}
data['result'] = {}
data['result']['0'] = {}
data['result']['0']['polled'] = {}
self.data = data
+ poll = Poll({'name': 'poll'})
+ poll_id = str(poll.save())
+ self.poll = Poll.get(poll_id)
+
def test_it_should_respond_to_pollster_username(self):
data = self.data
pollster_username = "encuestador1"
@@ -97,9 +105,8 @@ class PollResultFileTest(MongoTestCase):
self.assertEqual(expected_time_string, time_string)
def test_it_should_be_available_for_his_related_poll_when_it_saves(self):
- poll = Poll({'name': 'poll'})
- poll_id = str(poll.save())
- poll = Poll.get(poll_id)
+ poll = self.poll
+ poll_id = poll.id.__str__()
self.assertEqual(0, len(poll.get_result_files()))
data = self.data
@@ -112,9 +119,8 @@ class PollResultFileTest(MongoTestCase):
self.assertEqual(1, len(poll.get_result_files()))
def test_it_should_saves_with_a_chosen_name(self):
- poll = Poll({'name': 'poll'})
- poll_id = str(poll.save())
- poll = Poll.get(poll_id)
+ poll = self.poll
+ poll_id = poll.id.__str__()
self.assertEqual(0, len(poll.get_result_files()))
data = self.data
@@ -137,9 +143,8 @@ class PollResultFileTest(MongoTestCase):
self.assertEqual(expected_data, poll_result_file.get_data())
def test_it_should_respond_with_absolute_url_for_poll_result_file(self):
- poll = Poll({'name': 'poll'})
- poll_id = str(poll.save())
- poll = Poll.get(poll_id)
+ poll = self.poll
+ poll_id = poll.id.__str__()
data = self.data
data['poll_id'] = poll_id
@@ -150,6 +155,55 @@ class PollResultFileTest(MongoTestCase):
settings.RESULT_BCK_URL, poll_id, result_file.name)
self.assertEqual(expected_url, result_file.get_absolute_url())
+ def test_it_should_respond_with_hash(self):
+ data = {}
+ expected_hash = hashlib.md5(str(data)).hexdigest()
+
+ data["upload_timestamp"] = "timestamp"
+ file_path = make_temp_file(data)
+ result_file = PollResultFile(file_path)
+
+ self.assertEqual(expected_hash, result_file.hash)
+
+
+class ExistenceTest(MongoTestCase):
+
+ def setUp(self):
+ poll = Poll({'name': 'poll'})
+ poll_id = str(poll.save())
+ self.poll = Poll.get(poll_id)
+
+ def test_exists_when_other_poll_result_file_has_same_name(self):
+ poll = self.poll
+ poll_id = poll.id.__str__()
+ data = {}
+ data['poll_id'] = poll_id
+
+ file_path = make_temp_file(data)
+ result_file = PollResultFile(file_path)
+ self.assertFalse(result_file.exists())
+
+ result_file.save()
+ self.assertTrue(result_file.exists())
+
+ def test_it_should_respond_True_when_content_exists_already(self):
+ poll = self.poll
+ poll_id = poll.id.__str__()
+ self.assertEqual(0, len(poll.get_result_files()))
+
+ data = {}
+ data['poll_id'] = poll_id
+
+ file_path = make_temp_file(data)
+ original_result_file = PollResultFile(file_path)
+ original_result_file.save()
+ self.assertEqual(1, len(poll.get_result_files()))
+
+ file_path = make_temp_file(data)
+ duplicated_result_file = PollResultFile(file_path)
+
+ self.assertTrue(duplicated_result_file.exists())
+
class RueeTest(MongoTestCase):
@@ -195,3 +249,53 @@ class RemovePollResultFileTest(TestCase):
result_file.delete()
saved_file_path = result_file.file_path
self.assertFalse(os.path.exists(saved_file_path))
+
+
+class AuthoredByTest(TestCase):
+
+ def test_it_should_be_True_if_user_is_in_result_file(self):
+ username = "Is my result"
+ user = Mock()
+ user.username = username
+ file_path = "a_path"
+ with patch('__builtin__.open'), patch('polls.models.json'):
+ prf = PollResultFile(file_path)
+ prf.get_pollster_username = Mock(return_value=username)
+ self.assertTrue(prf.is_authored_by(user))
+
+ def test_it_should_be_False_if_user_is_not_in_result_file(self):
+ username = "Is not my result"
+ user = Mock()
+ user.username = username
+ file_path = "a_path"
+ with patch('__builtin__.open'), patch('polls.models.json'):
+ prf = PollResultFile(file_path)
+ prf.get_pollster_username = Mock(return_value="Other pollster")
+ self.assertFalse(prf.is_authored_by(user))
+
+
+class PollAssignationTest(TestCase):
+
+ def setUp(self):
+ self.poll_id = "poll id"
+ self.user = Mock(pollster=Mock())
+ file_path = "a_path"
+ with patch('__builtin__.open'), patch('polls.models.json'):
+ self.prf = PollResultFile(file_path)
+ self.prf.get_data = Mock(return_value={"poll_id": self.poll_id})
+
+ def test_it_return_True_if_user_is_assigned_to_poll_in_result(self):
+ user = self.user
+ prf = self.prf
+ mock_poll_id = Mock(id=self.poll_id)
+ with patch('polls.models.Poll') as PollMock:
+ PollMock.assigned_to_pollster.return_value = [mock_poll_id]
+ self.assertTrue(prf.poll_is_assigned_to(user))
+
+ def test_it_return_False_if_user_is_not_assigned_to_poll_in_result(self):
+ user = self.user
+ prf = self.prf
+ mock_poll_id = Mock(id="poll id 2")
+ with patch('polls.models.Poll') as PollMock:
+ PollMock.assigned_to_pollster.return_value = [mock_poll_id]
+ self.assertFalse(prf.poll_is_assigned_to(user))
diff --git a/webapp/polls/tests/poll_tests.py b/webapp/polls/tests/poll_tests.py
index 84a0fe0..832926d 100644
--- a/webapp/polls/tests/poll_tests.py
+++ b/webapp/polls/tests/poll_tests.py
@@ -13,12 +13,15 @@ from pollster.models import Pollster
from django.conf import settings
from django.test import TestCase
-from utils.test import MongoTestCase
+from utils.test import MongoTestCase, create_results_dir
from polls.tests.poll_result_file_tests import make_temp_file
class PollTests(MongoTestCase):
+ def setUp(self):
+ create_results_dir()
+
def test_poll_init(self):
pollster = Pollster.create(username="test", password="test")
@@ -430,6 +433,8 @@ class PollFormTests(MongoTestCase):
class PollResultFilesTest(MongoTestCase):
def setUp(self):
+ create_results_dir()
+
name = 'nombre de encuesta'
data = {'name': name}
poll = Poll(data=data)
@@ -462,6 +467,8 @@ class PollResultFilesTest(MongoTestCase):
class AddResultFilesTest(MongoTestCase):
def setUp(self):
+ create_results_dir()
+
name = 'nombre de encuesta'
data = {'name': name}
poll = Poll(data=data)
@@ -511,6 +518,9 @@ class CleanDataMustCheckImagesTypes(TestCase):
class RemoveResultsTest(MongoTestCase):
+ def setUp(self):
+ create_results_dir()
+
def test_it_should_respond_to_remove_results(self):
name = 'poll'
data = {'name': name}
diff --git a/webapp/polls/views.py b/webapp/polls/views.py
index c19eac1..526cabc 100644
--- a/webapp/polls/views.py
+++ b/webapp/polls/views.py
@@ -1,7 +1,6 @@
+# pylint: disable=C0111
# -*- encoding: utf-8 -*-
import os
-import json
-import StringIO
import warnings
from importlib import import_module
@@ -23,11 +22,9 @@ from django.conf import settings
from utils.forms import BadFormValidation
from utils.data_structure import dict_merge
-from polls.models import (WIDGET_TYPES, Structure, Poll, PollResult,
- PollResultFile)
+from polls.models import (WIDGET_TYPES, Structure, Poll, PollResultFile)
from polls.models import is_image_file
from polls.forms import PollForm
-from pollster.models import Pollster
module_path = settings.CLOCK_CLASS.split('.')[:-1]
@@ -357,102 +354,69 @@ class UnploadPollResultFormView(TemplateView):
template_name = "poll-result-form.html"
- def post(self, request, *args, **kwargs):
+ def post(self, request, *args, **kwargs): # pylint: disable=W0613
context = self.get_context_data()
+ user = request.user
files = dict(request.FILES.lists()).get('result', [])
- # si se subió algún archivo:
- if len(files):
- # Esto hace todo
-
- to_json = []
-
- # genera una lista de dict python en to_json
- for file in files:
- json_dst = StringIO.StringIO()
- for chunk in file.chunks():
- json_dst.write(chunk)
- json_dst.seek(0)
- to_json.append(json.load(json_dst, 'utf-8'))
- file.seek(0)
-
- # comprueba si los archivos ya existían y los excluye
- poll_id = to_json[0].get("poll_id", None)
- results_path = "%s/%s" % (settings.RESULT_BCK_ROOT, poll_id)
- uploaded_files = []
- for index, file in enumerate(files):
- file_path = "%s/%s" % (results_path, file.name)
- if os.path.exists(file_path):
- uploaded_files.append(file.name)
- del files[index]
-
- if len(uploaded_files):
- msg = u'Los siguientes resultados ya se encuentran \
- publicados: %s y no serán procesados.' % (
- ", ".join(uploaded_files))
- messages.add_message(self.request, messages.INFO, msg)
-
- # si no hay más archivos, vuelve al usuario
- if not len(files):
- return self.render_to_response(context)
-
- # revisa si el primero de los archivos es del usuario actual
- # si no, vuelve al usuario
- if len(to_json):
- pollster_id = to_json[0].get("pollster_id", None)
- if str(request.user.pollster.id) != pollster_id:
- pollster_username = to_json[0].get(
- "pollster_username", None)
- if not pollster_username:
- pollster_username = "Desconocido!"
- msg = u'El sistema cree que este archivo resultado \
- no pertence a una encuesta realizada por usted. \
- Asegúrese de estar usando el mismo usuario que \
- utilizó para descargar este modelo de encuesta. \
- Usuario esperado: %s.' % pollster_username
- messages.add_message(request, messages.ERROR, msg)
- return self.render_to_response(context)
-
- # crea un poll result con todos los archivos implicados
- poll_result = PollResult(to_json)
-
- poll = poll_result.get_poll()
- pollster = Pollster.get_by_user_id(request.user.id)
-
- # valida que el pollster esté asignado a la poll en cuestión
- assigned_polls_id = [
- p.id for p in poll.assigned_to_pollster(pollster)]
-
- if poll.id not in assigned_polls_id:
- msg = u'Estos son resultados de una encuesta \
- que no le fué asignada.'
+ if not len(files):
+ msg = u'Necesita seleccionar un archivo.'
+ messages.add_message(self.request, messages.INFO, msg)
+
+ processed_files = []
+ existing = []
+ not_authored_by_user = []
+ poll_not_assigned_to_user = []
+
+ date_time_string = Clock.get_time_string()
+ for file_ in files:
+ file_name = file_.name
+ tmp_file_path = file_.temporary_file_path()
+ try:
+ prf = PollResultFile(tmp_file_path)
+ if prf.exists():
+ existing.append(file_name)
+ elif not prf.is_authored_by(user):
+ not_authored_by_user.append(file_name)
+ elif not prf.poll_is_assigned_to(user):
+ poll_not_assigned_to_user.append(file_name)
+ else:
+ prf.name = file_name
+ prf.set_upload_timestamp(date_time_string)
+ prf.save()
+ processed_files.append(file_name)
+ except ValueError:
+ fname = file_.name
+ msg = u'{0}: No es un .poll_result válido.'.format(fname)
messages.add_message(self.request, messages.ERROR, msg)
- else:
- # End validations
-
- date_time_string = Clock.get_time_string()
- uploaded_files = [
- (f.name, f.temporary_file_path()) for f in files
- ]
- for name, path in uploaded_files:
- result_file = PollResultFile(path)
- result_file.name = name
- result_file.set_upload_timestamp(date_time_string)
- result_file.save()
-
- processed_files = [file.name for file in files]
- messages.add_message(
- self.request,
- messages.SUCCESS,
- u'Los resultados se guardaron con éxito.\
- Los siguientes archivos fueron procesados: \
- %s' % ", ".join(processed_files)
- )
- # si no hay ningún archivo
- else:
- msg = u'Necesita seleccionar un archivo.'
+ if len(existing):
+ msg = u'Los siguientes resultados ya se encuentran \
+ publicados: %s y no serán procesados.' % (", ".join(existing))
messages.add_message(self.request, messages.INFO, msg)
+ if len(not_authored_by_user):
+ msg = u'El sistema cree que estos archivos no pertencen a una \
+ encuesta realizada por usted: {0}'.format(
+ ", ".join(not_authored_by_user)
+ )
+ messages.add_message(request, messages.ERROR, msg)
+
+ if len(poll_not_assigned_to_user):
+ msg = u'Estos son resultados de una encuesta \
+ que no le fué asignada. {0}'.format(
+ ", ".join(poll_not_assigned_to_user)
+ )
+ messages.add_message(self.request, messages.ERROR, msg)
+
+ if len(processed_files):
+ messages.add_message(
+ self.request,
+ messages.SUCCESS,
+ u'Los resultados se guardaron con éxito.\
+ Los siguientes archivos fueron procesados: \
+ %s' % ", ".join(processed_files)
+ )
+
return self.render_to_response(context)
diff --git a/webapp/pollster/fixtures/generic_pollster.json b/webapp/pollster/fixtures/generic_pollster.json
new file mode 100644
index 0000000..ce35a0c
--- /dev/null
+++ b/webapp/pollster/fixtures/generic_pollster.json
@@ -0,0 +1,22 @@
+[
+ {
+ "pk": 33,
+ "model": "auth.user",
+ "fields": {
+ "username": "encuestador",
+ "first_name": "",
+ "last_name": "",
+ "is_active": true,
+ "is_superuser": false,
+ "is_staff": false,
+ "last_login": "2013-10-01T13:56:24.949Z",
+ "groups": [
+ 2
+ ],
+ "user_permissions": [],
+ "password": "pbkdf2_sha256$10000$8U3hB7kUxclx$3H89EMDKOjkjK0RtArQrbx8akFmpfwSUq9hIfXH64Aw=",
+ "email": "",
+ "date_joined": "2013-10-01T13:56:24.949Z"
+ }
+ }
+]
diff --git a/webapp/pollster/fixtures/mongo_generic_pollster.json b/webapp/pollster/fixtures/mongo_generic_pollster.json
new file mode 100644
index 0000000..2aac91f
--- /dev/null
+++ b/webapp/pollster/fixtures/mongo_generic_pollster.json
@@ -0,0 +1,5 @@
+{
+ "_id": {"$oid": "52040926421aa913c3bd4506" },
+ "username": "encuestador",
+ "user_id": 33
+}
diff --git a/webapp/sociologist/poll_urls.py b/webapp/sociologist/poll_urls.py
index 6f2a1a4..795f968 100644
--- a/webapp/sociologist/poll_urls.py
+++ b/webapp/sociologist/poll_urls.py
@@ -1,3 +1,4 @@
+# pylint: disable=E1120
from django.conf.urls.defaults import patterns, url
from polls.views import *
diff --git a/webapp/utils/test.py b/webapp/utils/test.py
index 9148317..c2faac7 100644
--- a/webapp/utils/test.py
+++ b/webapp/utils/test.py
@@ -1,6 +1,9 @@
+# pylint: disable=C0111
import StringIO
import Image
import shutil
+import glob
+import os
from django.conf import settings
from django.test import TestCase
@@ -12,7 +15,7 @@ from utils.mongo_connection import connect, disconnect
disconnect()
-class MongoTestCase(TestCase):
+class MongoTestCase(TestCase): # pylint: disable=R0904
def __init__(self, methodName='runtest'):
db_name = 'test_%s' % settings.MONGO_SETTINGS['NAME']
@@ -62,3 +65,17 @@ def mock_in_memory_image(name='foo.jpg', format="jpeg", size=(200, 200)):
def remove_option_images_dir():
shutil.rmtree(settings.IMAGE_OPTIONS_ROOT, ignore_errors=True)
+
+
+def empty_results_dir():
+ results_dir_contents = glob.glob(settings.RESULT_BCK_ROOT + "/*")
+ for i in results_dir_contents:
+ shutil.rmtree(i, ignore_errors=True)
+
+
+def create_results_dir():
+ dir_ = settings.RESULT_BCK_ROOT
+ try:
+ os.mkdir(dir_)
+ except OSError:
+ pass
diff --git a/webapp/webapp/features/cannot_modify_poll_structure.feature b/webapp/webapp/features/cannot_modify_poll_structure.feature
index a424bdd..011f723 100644
--- a/webapp/webapp/features/cannot_modify_poll_structure.feature
+++ b/webapp/webapp/features/cannot_modify_poll_structure.feature
@@ -6,7 +6,7 @@ Feature: Researcher can't modify poll's structure
Scenario: a poll with results
Given I am logged in as "Researcher"
- And "poll" exists
- And "poll" has "simple.poll_result"
- When I visit the "Modificar estructura" page for "poll" poll
+ And "open_poll" exists
+ And "open_poll" has "simple.poll_result"
+ When I visit the "Modificar estructura" page for "open_poll" poll
Then I should see a message that says "No puede modificar"
diff --git a/webapp/webapp/features/fixtures/invalid.poll_result b/webapp/webapp/features/fixtures/invalid.poll_result
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webapp/webapp/features/fixtures/invalid.poll_result
diff --git a/webapp/webapp/features/fixtures/not_asigned_poll.poll_result b/webapp/webapp/features/fixtures/not_asigned_poll.poll_result
new file mode 100644
index 0000000..68bc8b3
--- /dev/null
+++ b/webapp/webapp/features/fixtures/not_asigned_poll.poll_result
@@ -0,0 +1,6 @@
+{
+ "poll_id": "51d471b8f966f43d509a969b",
+ "pollster_id": "52040926421aa913c3bd4506",
+ "pollster_username": "encuestador",
+ "result": {}
+}
diff --git a/webapp/webapp/features/fixtures/other_owner.poll_result b/webapp/webapp/features/fixtures/other_owner.poll_result
new file mode 100644
index 0000000..4de0d8c
--- /dev/null
+++ b/webapp/webapp/features/fixtures/other_owner.poll_result
@@ -0,0 +1,6 @@
+{
+ "poll_id": "51d471b8f966f43d509a969a",
+ "pollster_id": "52040926421aa913c3bd450a",
+ "pollster_username": "other_owner",
+ "result": {}
+}
diff --git a/webapp/webapp/features/fixtures/same_time.poll_result b/webapp/webapp/features/fixtures/same_time.poll_result
new file mode 100644
index 0000000..7fe93c5
--- /dev/null
+++ b/webapp/webapp/features/fixtures/same_time.poll_result
@@ -0,0 +1,19 @@
+{
+ "poll_id": "51d471b8f966f43d509a969a",
+ "pollster_id": "52040926421aa913c3bd4506",
+ "pollster_username": "encuestador",
+ "result": {
+ "0":{
+ "answers":{},
+ "polled":{
+ "DEPARTAMENTO":"MONTEVIDEO",
+ "GRADO":"2",
+ "GRUPO":"A",
+ "ID":"0",
+ "NUM_ESC":"236",
+ "RUEE":"1101236",
+ "TIPO_GRUPO":"1"
+ }
+ }
+ }
+}
diff --git a/webapp/webapp/features/fixtures/same_time_copy.poll_result b/webapp/webapp/features/fixtures/same_time_copy.poll_result
new file mode 100644
index 0000000..7fe93c5
--- /dev/null
+++ b/webapp/webapp/features/fixtures/same_time_copy.poll_result
@@ -0,0 +1,19 @@
+{
+ "poll_id": "51d471b8f966f43d509a969a",
+ "pollster_id": "52040926421aa913c3bd4506",
+ "pollster_username": "encuestador",
+ "result": {
+ "0":{
+ "answers":{},
+ "polled":{
+ "DEPARTAMENTO":"MONTEVIDEO",
+ "GRADO":"2",
+ "GRUPO":"A",
+ "ID":"0",
+ "NUM_ESC":"236",
+ "RUEE":"1101236",
+ "TIPO_GRUPO":"1"
+ }
+ }
+ }
+}
diff --git a/webapp/webapp/features/fixtures/valid.poll_result b/webapp/webapp/features/fixtures/valid.poll_result
new file mode 100644
index 0000000..d042f1d
--- /dev/null
+++ b/webapp/webapp/features/fixtures/valid.poll_result
@@ -0,0 +1,6 @@
+{
+ "poll_id": "51d471b8f966f43d509a969a",
+ "pollster_id": "52040926421aa913c3bd4506",
+ "pollster_username": "encuestador",
+ "result": {}
+}
diff --git a/webapp/webapp/features/fixtures/valid_copy.poll_result b/webapp/webapp/features/fixtures/valid_copy.poll_result
new file mode 100644
index 0000000..d042f1d
--- /dev/null
+++ b/webapp/webapp/features/fixtures/valid_copy.poll_result
@@ -0,0 +1,6 @@
+{
+ "poll_id": "51d471b8f966f43d509a969a",
+ "pollster_id": "52040926421aa913c3bd4506",
+ "pollster_username": "encuestador",
+ "result": {}
+}
diff --git a/webapp/webapp/features/remove_poll_results_from_poll.py b/webapp/webapp/features/remove_poll_results_from_poll.py
index 6b84c47..d5cbfff 100644
--- a/webapp/webapp/features/remove_poll_results_from_poll.py
+++ b/webapp/webapp/features/remove_poll_results_from_poll.py
@@ -1,17 +1,19 @@
+# pylint disable=C0111
import json
from lettuce import step, world
from nose.tools import assert_false, assert_true
-from steps import login, get_fixture, create_poll_result_file, click_on
-from polls.models import Poll
+from steps import (login, get_fixture, create_poll_result_file, click_on,
+ get_poll_by_name)
-@step(u'Given I am logged in as "([^"]*)"')
-def given_i_am_logged_in_as_rol(step, rol):
+@step(u'I am logged in as "([^"]*)"')
+def i_am_logged_in_as_rol(step, rol):
roles2generic_users = {
'Administrator': 'admin',
- 'Researcher': 'researcher'
+ 'Researcher': 'researcher',
+ 'Pollster': 'encuestador'
}
browser = world.browser
username = roles2generic_users[rol]
@@ -21,9 +23,10 @@ def given_i_am_logged_in_as_rol(step, rol):
@step(u'And "([^"]*)" has "([^"]*)"')
-def and_poll_has_poll_result(step, poll_name, poll_result_name):
+def poll_has_result(step, poll_name, poll_result_name):
poll_result_path = get_fixture(poll_result_name)
- poll_id = world.poll_id.__str__()
+ poll_id = str(get_poll_by_name(poll_name).id)
+ poll = get_poll_by_name(poll_name)
with open(poll_result_path) as f:
poll_result_data = json.load(f, "utf-8")
@@ -33,7 +36,6 @@ def and_poll_has_poll_result(step, poll_name, poll_result_name):
poll_result_path = create_poll_result_file(poll_result_data,
poll_result_name)
- poll = Poll.get(poll_id)
path_and_name = (poll_result_path, poll_result_name)
poll.add_result_files([path_and_name])
diff --git a/webapp/webapp/features/researcher_adds_images_to_options.py b/webapp/webapp/features/researcher_adds_images_to_options.py
index 35ace35..b651c50 100644
--- a/webapp/webapp/features/researcher_adds_images_to_options.py
+++ b/webapp/webapp/features/researcher_adds_images_to_options.py
@@ -2,7 +2,6 @@ import os
from lettuce import step, world
from nose.tools import assert_true, assert_equals
-from django.conf import settings
from steps import click_on
@@ -36,6 +35,9 @@ def add_a_question_as_question_type(step, question, question_type):
@step(u'And add a option "([^"]*)" with weight "([^"]*)" and image "([^"]*)"')
def add_option_with_weight_and_image(step, option, weight, image):
b = world.browser
+ fixtures_path = world.fixtures_path
+ img_path = os.path.join(fixtures_path, image)
+
add_option = b.find_by_xpath(
'//*[@id="WGroupContainer"]/div/fieldset/div/div[3]/div[1]/div/button')
add_option.click()
@@ -44,8 +46,6 @@ def add_option_with_weight_and_image(step, option, weight, image):
opt_id = b.find_by_xpath(p).text
b.fill('groups.0.fields.0.options.{id}.text'.format(id=opt_id), option)
b.fill('groups.0.fields.0.options.{id}.weight'.format(id=opt_id), weight)
- fixtures_path = os.path.join(settings.PROJECT_ROOT, 'features/fixtures')
- img_path = os.path.join(fixtures_path, image)
input_ = 'groups.0.fields.0.options.{id}.img'.format(id=opt_id)
script = """
a = $('input[name="{name}"]');
diff --git a/webapp/webapp/features/steps.py b/webapp/webapp/features/steps.py
index 4c7d687..d696d51 100644
--- a/webapp/webapp/features/steps.py
+++ b/webapp/webapp/features/steps.py
@@ -60,7 +60,10 @@ def create_poll(name, status=Poll.OPEN):
@step(u'And "([^"]*)" exists')
def and_poll_name_exists(step, poll_name):
- create_poll(poll_name)
+ try:
+ get_poll_by_name(poll_name)
+ except IndexError:
+ create_poll(poll_name)
@step(u'And "([^"]*)" is "([^"]*)"')
@@ -77,8 +80,10 @@ def and_encuestador_is_binded_to_poll(step, encuestador, poll_name):
pollster = get_pollster_by_username(encuestador)
except IndexError:
pollster = Pollster.create(username=username, password=password)
- polls = [world.poll_id]
+ poll_id = get_poll_by_name(poll_name).id.__str__()
+ polls = [poll_id]
Poll.pollster_assignment(pollster.id, polls)
+ world.poll_id = poll_id
def get_fixture(poll_result):
@@ -110,14 +115,14 @@ def poll_result_uploaded_by_encuestador(step, poll_result_name,
shutil.move(poll_result_path, results_dir)
-@step(u'Then I should see a message that says "([^"]*)"$')
+@step(u'I should see a message that says "([^"]*)"$')
def i_should_see_a_message_that_says_text(step, text):
b = world.browser
assert_true(b.is_text_present(text))
def get_poll_by_name(poll_name):
- return filter(lambda p: p.name == poll_name, Poll.all())[0]
+ return [poll for poll in Poll.all() if poll.name == poll_name][0]
@step(u'I visit the "([^"]*)" page for "([^"]*)" poll')
diff --git a/webapp/webapp/features/terrain.py b/webapp/webapp/features/terrain.py
index ed52bf6..e3caeb2 100644
--- a/webapp/webapp/features/terrain.py
+++ b/webapp/webapp/features/terrain.py
@@ -1,3 +1,5 @@
+import os
+
from lettuce import world, before, after
from splinter import Browser
from fabric.api import local
@@ -5,12 +7,16 @@ from fabric.context_managers import hide
from django.conf import settings
from django.core import management
-from utils.test import remove_option_images_dir
+from utils.test import (remove_option_images_dir, empty_results_dir,
+ create_results_dir)
@before.all
def set_browser():
world.browser = Browser('phantomjs')
+ world.fixtures_path = os.path.join(settings.PROJECT_ROOT,
+ 'features/fixtures')
+ create_results_dir()
@after.all
@@ -34,14 +40,40 @@ def load_fixture(fixture_name):
verbosity=0)
+def load_mongo_fixture(fixture_name, collection):
+ pollster_fixture_dir = os.path.join(settings.PROJECT_ROOT,
+ '../pollster/fixtures')
+ polls_fixture_dir = os.path.join(settings.PROJECT_ROOT,
+ '../polls/fixtures')
+ fixtures = {
+ 'pollsters': pollster_fixture_dir,
+ 'polls': polls_fixture_dir,
+ }
+ fixture_dir = fixtures[collection]
+ fixture_path = os.path.join(fixture_dir, fixture_name + ".json")
+ kwargs = {
+ 'db': settings.MONGO_SETTINGS['NAME'],
+ 'collection': collection,
+ 'fixture': fixture_path,
+ }
+ cmd = "mongoimport -d {db} -c {collection} --file {fixture} --jsonArray"
+ local(cmd.format(**kwargs))
+
+
@before.each_feature
def before_each_feature(feature):
"""This is the main lettuce hook "@before.each_feature"."""
drop_mongo()
drop_sqlite()
+ empty_results_dir()
if feature.name in ("Researcher adds images to options",
- "Researcher can't modify poll's structure"):
+ "Researcher can't modify poll's structure",
+ "Upload .poll_result files"):
load_fixture("generic_researcher")
+ load_fixture("generic_pollster")
+ load_mongo_fixture("mongo_generic_pollster", "pollsters")
+ load_mongo_fixture("closed_poll", "polls")
+ load_mongo_fixture("poll", "polls")
@after.each_feature
diff --git a/webapp/webapp/features/upload_poll_result.feature b/webapp/webapp/features/upload_poll_result.feature
index fa01a95..5ce7367 100644
--- a/webapp/webapp/features/upload_poll_result.feature
+++ b/webapp/webapp/features/upload_poll_result.feature
@@ -4,11 +4,69 @@ Feature: Upload .poll_result files
So that researcher can compute them like a chunk of the whole poll result
Scenario: Upload one valid .poll_result file
- Given I am a pollster: "encuestador1"
- And "poll1" is "Cerrada"
- And "encuestador1" is binded to "poll1"
- And "valid.poll_result" is authored by "encuestador1"
+ Given I am logged in as "Pollster"
+ And "closed_poll" exists
+ And "encuestador" is binded to "closed_poll"
+ And "valid.poll_result" is authored by "encuestador"
When I visit the "upload" page
- And I upload "valid.poll_result" on "31/12/1999 23:59hs"
+ And I upload "valid.poll_result"
Then I should see a message that says "valid.poll_result" and "éxito"
And "valid.poll_result" has the time string "31/12/1999 23:59hs"
+
+ Scenario: Invalid .poll_result file
+ Given I am logged in as "Pollster"
+ When I visit the "upload" page
+ And I upload "invalid.poll_result"
+ Then I should see a message that says "invalid.poll_result"
+ And I should see a message that says "No es un .poll_result válido."
+
+ Scenario: Upload .poll_result file that exists already
+ Given I am logged in as "Pollster"
+ And "closed_poll" exists
+ And "encuestador" is binded to "closed_poll"
+ And "valid.poll_result" is authored by "encuestador"
+ When I visit the "upload" page
+ And I upload "valid.poll_result"
+ When I visit the "upload" page
+ And I upload "valid.poll_result"
+ Then I should see a message that says "valid.poll_result"
+ And I should see a message that says "ya se encuentran publicados"
+
+ Scenario: Upload .poll_result file which its content had been uploaded
+ Given I am logged in as "Pollster"
+ And "closed_poll" exists
+ And "encuestador" is binded to "closed_poll"
+ And "valid.poll_result" is authored by "encuestador"
+ When I visit the "upload" page
+ And I upload "valid.poll_result"
+ And "valid_copy.poll_result" is authored by "encuestador"
+ When I visit the "upload" page
+ And I upload "valid_copy.poll_result"
+ Then I should see a message that says "valid_copy.poll_result"
+ And I should see a message that says "ya se encuentran publicados"
+
+ Scenario: Upload .poll_result wich its not authored by logged in pollster
+ Given I am logged in as "Pollster"
+ And "closed_poll" exists
+ When I visit the "upload" page
+ And I upload "other_owner.poll_result"
+ Then I should see a message that says "no pertencen a una encuesta realizada por usted"
+
+ Scenario: Upload .poll_result with a poll not assigned to logged in pollster
+ Given I am logged in as "Pollster"
+ And "poll" exists
+ When I visit the "upload" page
+ And I upload "not_asigned_poll.poll_result"
+ Then I should see a message that says "Estos son resultados de una encuesta que no le fué asignada."
+
+ Scenario: Upload two .poll_result with the same content at the same time
+ Given I am logged in as "Pollster"
+ And "poll" exists
+ When I visit the "upload" page
+ And I load "same_time.poll_result" on position "1"
+ And I load "same_time_copy.poll_result" on position "2"
+ When I upload loaded files
+ Then I should see a message that says "same_time.poll_result"
+ And I should see a message that says "éxito"
+ And I should see a message that says "same_time_copy.poll_result"
+ And I should see a message that says "ya se encuentran publicados"
diff --git a/webapp/webapp/features/upload_poll_result.py b/webapp/webapp/features/upload_poll_result.py
index dc15c42..1ed2650 100644
--- a/webapp/webapp/features/upload_poll_result.py
+++ b/webapp/webapp/features/upload_poll_result.py
@@ -1,29 +1,59 @@
# -*- coding: utf-8 -*-
+import os
+
from lettuce import step, world
from nose.tools import assert_true, assert_equals
-from polls.models import Poll
-from poll_result_details import (create_poll_result_file,
- get_pollster_by_username)
+from polls.models import Poll, PollResultFile
@step(u'And "([^"]*)" is authored by "([^"]*)"')
def result_file_is_authored_by_pollster(step, file_name, pollster_username):
- pollster = get_pollster_by_username(pollster_username)
- data = {}
- data['poll_id'] = world.poll_id.__str__()
- data['pollster_username'] = pollster.username
- data['pollster_id'] = pollster.id.__str__()
- data['result'] = {}
- world.poll_result_path = create_poll_result_file(data, file_name)
+ fixtures_path = world.fixtures_path
+ file_path = os.path.join(fixtures_path, file_name)
+ rf = PollResultFile(file_path)
+ assert_equals(pollster_username, rf.get_pollster_username())
-@step(u'And I upload "([^"]*)" on "([^"]*)"')
-def upload_file_name_on_time_string(step, file_name, time_string):
- b = world.browser
+def get_result_file_path_from_fixture(file_name):
+ fixtures_path = world.fixtures_path
+ result_file_path = os.path.join(fixtures_path, file_name)
+ return result_file_path
+
+
+def load_file(browser, file_name, position=1):
+ b = browser
+ poll_result_path = get_result_file_path_from_fixture(file_name)
b.find_by_xpath('/html/body/div/div[2]/form/fieldset/div/button').click()
- b.attach_file('result', world.poll_result_path)
- b.find_by_xpath('/html/body/div/div[2]/form/div[1]/div/button').click()
+ input_xpath = "(//input[@name='result'])[{0}]".format(str(position))
+ file_input = b.find_by_xpath(input_xpath).first
+ file_input.type(poll_result_path)
+
+
+def click_on_by_xpath(browser, xpath):
+ b = browser
+ b.find_by_xpath(xpath).click()
+
+
+@step(u'And I load "([^"]*)" on position "([^"]*)"')
+def load_file_name(step, file_name, position):
+ b = world.browser
+ load_file(b, file_name, position)
+
+
+@step(u'When I upload loaded files')
+def when_i_upload_loaded_files(step):
+ b = world.browser
+ xpath = '/html/body/div/div[2]/form/div[1]/div/button'
+ click_on_by_xpath(b, xpath)
+
+
+@step(u'I upload "([^"]*)"')
+def upload_file_name(step, file_name):
+ b = world.browser
+ load_file(b, file_name)
+ xpath = '/html/body/div/div[2]/form/div[1]/div/button'
+ click_on_by_xpath(b, xpath)
@step(u'Then I should see a message that says "([^"]*)" and "([^"]*)"')
diff --git a/webapp/webapp/test_settings.py b/webapp/webapp/test_settings.py
index 9f96791..0f1418d 100644
--- a/webapp/webapp/test_settings.py
+++ b/webapp/webapp/test_settings.py
@@ -30,7 +30,7 @@ LETTUCE_SERVER_PORT = 63001
DATABASES['default']['TEST_NAME'] = '/tmp/testserver.db'
-RESULT_BCK_ROOT = '/tmp'
+RESULT_BCK_ROOT = '/tmp/results_bck'
class MockClock(object):