From 970eab40fae16e4318cd97d7801ecb8b44857bf1 Mon Sep 17 00:00:00 2001 From: Code Raguet Date: Fri, 04 Oct 2013 18:41:30 +0000 Subject: Merge branch 'DEV' --- 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): -- cgit v0.9.1