def test_edit_updated_geopoint_cache(self): query_args = { 'username': self.user.username, 'id_string': self.xform.id_string, 'query': '{}', 'fields': '[]', 'sort': '[]', 'count': True } xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml") self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) # query mongo for the _geopoint field query_args['count'] = False records = list(ParsedInstance.query_mongo(**query_args)) self.assertEqual(len(records), 1) # submit the edited instance xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml") self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) records = list(ParsedInstance.query_mongo(**query_args)) self.assertEqual(len(records), 1) cached_geopoint = records[0][GEOLOCATION] # the cached geopoint should equal the gps field gps = records[0]['gps'].split(" ") self.assertEqual(float(gps[0]), float(cached_geopoint[0])) self.assertEqual(float(gps[1]), float(cached_geopoint[1]))
def test_xform_delete_cascades_mongo_instances(self): initial_mongo_count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]["count"] # submit instance for i in range(len(self.surveys)): self._submit_transport_instance(i) # check mongo record exists mongo_count = ParsedInstance.query_mongo(self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]["count"] self.assertEqual(mongo_count, initial_mongo_count + len(self.surveys)) # delete form xform_delete_url = reverse(delete_xform, kwargs={ 'username': self.user.username, 'id_string': self.xform.id_string }) self.client.post(xform_delete_url) mongo_count = ParsedInstance.query_mongo(self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]["count"] self.assertEqual(mongo_count, initial_mongo_count)
def test_deleted_submission_not_in_export(self): self._publish_transportation_form() initial_count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]['count'] self._submit_transport_instance(0) self._submit_transport_instance(1) count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]['count'] self.assertEqual(count, initial_count + 2) # get id of second submission instance_id = Instance.objects.filter( xform=self.xform).order_by('id').reverse()[0].id delete_url = reverse( delete_data, kwargs={"username": self.user.username, "id_string": self.xform.id_string}) params = {'id': instance_id} self.client.post(delete_url, params) count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]['count'] self.assertEqual(count, initial_count + 1) # create the export csv_export_url = reverse( 'csv_export', kwargs={"username": self.user.username, "id_string": self.xform.id_string}) response = self.client.get(csv_export_url) self.assertEqual(response.status_code, 200) f = StringIO.StringIO(self._get_response_content(response)) csv_reader = csv.reader(f) num_rows = len([row for row in csv_reader]) f.close() # number of rows == 2 i.e. initial_count + header plus one row self.assertEqual(num_rows, initial_count + 2)
def test_edit_updated_geopoint_cache(self): query_args = { 'username': self.user.username, 'id_string': self.xform.id_string, 'query': '{}', 'fields': '[]', 'sort': '[]', 'count': True } xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml" ) self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) # query mongo for the _geopoint field query_args['count'] = False records = ParsedInstance.query_mongo(**query_args) self.assertEqual(len(records), 1) # submit the edited instance xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml" ) self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) records = ParsedInstance.query_mongo(**query_args) self.assertEqual(len(records), 1) cached_geopoint = records[0][GEOLOCATION] # the cached geopoint should equal the gps field gps = records[0]['gps'].split(" ") self.assertEqual(float(gps[0]), float(cached_geopoint[0])) self.assertEqual(float(gps[1]), float(cached_geopoint[1]))
def test_edited_submission(self): """ Test submissions that have been edited """ xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml", ) num_instances_history = InstanceHistory.objects.count() num_instances = Instance.objects.count() query_args = { "username": self.user.username, "id_string": self.xform.id_string, "query": "{}", "fields": "[]", "sort": "[]", "count": True, } cursor = ParsedInstance.query_mongo(**query_args) num_mongo_instances = cursor[0]["count"] # make first submission self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) self.assertEqual(Instance.objects.count(), num_instances + 1) # no new record in instances history self.assertEqual(InstanceHistory.objects.count(), num_instances_history) # check count of mongo instances after first submission cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]["count"], num_mongo_instances + 1) # edited submission xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml", ) self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) # we must have the same number of instances self.assertEqual(Instance.objects.count(), num_instances + 1) # should be a new record in instances history self.assertEqual(InstanceHistory.objects.count(), num_instances_history + 1) cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]["count"], num_mongo_instances + 1) # make sure we edited the mongo db record and NOT added a new row query_args["count"] = False cursor = ParsedInstance.query_mongo(**query_args) record = cursor[0] with open(xml_submission_file_path, "r") as f: xml_str = f.read() xml_str = clean_and_parse_xml(xml_str).toxml() edited_name = re.match(ur"^.+?<name>(.+?)</name>", xml_str).groups()[0] self.assertEqual(record["name"], edited_name)
def test_edited_submission(self): """ Test submissions that have been edited """ xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml" ) num_instances_history = InstanceHistory.objects.count() num_instances = Instance.objects.count() query_args = { 'username': self.user.username, 'id_string': self.xform.id_string, 'query': '{}', 'fields': '[]', 'sort': '[]', 'count': True } cursor = ParsedInstance.query_mongo(**query_args) num_mongo_instances = cursor[0]['count'] # make first submission self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) self.assertEqual(Instance.objects.count(), num_instances + 1) # no new record in instances history self.assertEqual( InstanceHistory.objects.count(), num_instances_history) # check count of mongo instances after first submission cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # edited submission xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml" ) client = DigestClient() client.set_authorization('bob', 'bob', 'Digest') self._make_submission(xml_submission_file_path, client=client) self.assertEqual(self.response.status_code, 201) # we must have the same number of instances self.assertEqual(Instance.objects.count(), num_instances + 1) # should be a new record in instances history self.assertEqual( InstanceHistory.objects.count(), num_instances_history + 1) cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # make sure we edited the mongo db record and NOT added a new row query_args['count'] = False cursor = ParsedInstance.query_mongo(**query_args) record = cursor[0] with open(xml_submission_file_path, "r") as f: xml_str = f.read() xml_str = clean_and_parse_xml(xml_str).toxml() edited_name = re.match(ur"^.+?<name>(.+?)</name>", xml_str).groups()[0] self.assertEqual(record['name'], edited_name)
def test_edited_submission(self): """ Test submissions that have been edited """ xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml") num_instances_history = InstanceHistory.objects.count() num_instances = Instance.objects.count() query_args = { 'username': self.user.username, 'id_string': self.xform.id_string, 'query': '{}', 'fields': '[]', 'sort': '[]', 'count': True } cursor = ParsedInstance.query_mongo(**query_args) num_mongo_instances = cursor[0]['count'] # make first submission self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) self.assertEqual(Instance.objects.count(), num_instances + 1) # no new record in instances history self.assertEqual(InstanceHistory.objects.count(), num_instances_history) # check count of mongo instances after first submission cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # edited submission xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml") client = DigestClient() client.set_authorization('bob', 'bob', 'Digest') self._make_submission(xml_submission_file_path, client=client) self.assertEqual(self.response.status_code, 201) # we must have the same number of instances self.assertEqual(Instance.objects.count(), num_instances + 1) # should be a new record in instances history self.assertEqual(InstanceHistory.objects.count(), num_instances_history + 1) cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # make sure we edited the mongo db record and NOT added a new row query_args['count'] = False cursor = ParsedInstance.query_mongo(**query_args) record = cursor[0] with open(xml_submission_file_path, "r") as f: xml_str = f.read() xml_str = clean_and_parse_xml(xml_str).toxml() edited_name = re.match(r"^.+?<name>(.+?)</name>", xml_str).groups()[0] self.assertEqual(record['name'], edited_name)
def api(request, username=None, id_string=None): """ Returns all results as JSON. If a parameter string is passed, it takes the 'query' parameter, converts this string to a dictionary, an that is then used as a MongoDB query string. NOTE: only a specific set of operators are allow, currently $or and $and. Please send a request if you'd like another operator to be enabled. NOTE: Your query must be valid JSON, double check it here, http://json.parser.online.fr/ E.g. api?query='{"last_name": "Smith"}' """ if request.method == "OPTIONS": response = HttpResponse() add_cors_headers(response) return response helper_auth_helper(request) helper_auth_helper(request) xform, owner = check_and_set_user_and_form(username, id_string, request) if not xform: return HttpResponseForbidden(_(u'Not shared.')) try: args = { 'username': username, 'id_string': id_string, 'query': request.GET.get('query'), 'fields': request.GET.get('fields'), 'sort': request.GET.get('sort') } if 'start' in request.GET: args["start"] = int(request.GET.get('start')) if 'limit' in request.GET: args["limit"] = int(request.GET.get('limit')) if 'count' in request.GET: args["count"] = True if int(request.GET.get('count')) > 0\ else False cursor = ParsedInstance.query_mongo(**args) except ValueError as e: return HttpResponseBadRequest(e.__str__()) records = list(record for record in cursor) response_text = json_util.dumps(records) if 'callback' in request.GET and request.GET.get('callback') != '': callback = request.GET.get('callback') response_text = ("%s(%s)" % (callback, response_text)) response = HttpResponse(response_text, mimetype='application/json') add_cors_headers(response) return response
def test_xform_delete_cascades_mongo_instances(self): initial_mongo_count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, "{}", "[]", "{}", count=True )[0]["count"] # submit instance for i in range(len(self.surveys)): self._submit_transport_instance(i) # check mongo record exists mongo_count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, "{}", "[]", "{}", count=True )[0]["count"] self.assertEqual(mongo_count, initial_mongo_count + len(self.surveys)) # delete form xform_delete_url = reverse( delete_xform, kwargs={"username": self.user.username, "id_string": self.xform.id_string} ) self.client.post(xform_delete_url) mongo_count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, "{}", "[]", "{}", count=True )[0]["count"] self.assertEqual(mongo_count, initial_mongo_count)
def _query_mongo(self, query='{}', start=0, limit=ParsedInstance.DEFAULT_LIMIT, fields='[]', count=False): # ParsedInstance.query_mongo takes params as json strings # so we dumps the fields dictionary count_args = { 'username': self.username, 'id_string': self.id_string, 'query': query, 'fields': '[]', 'sort': '{}', 'count': True } count_object = ParsedInstance.query_mongo(**count_args) record_count = count_object[0]["count"] if record_count == 0: raise NoRecordsFoundError("No records found for your query") # if count was requested, return the count if count: return record_count else: query_args = { 'username': self.username, 'id_string': self.id_string, 'query': query, 'fields': fields, # TODO: we might want to add this in for the user # to sepcify a sort order 'sort': '{}', 'start': start, 'limit': limit, 'count': False } # use ParsedInstance.query_mongo cursor = ParsedInstance.query_mongo(**query_args) return cursor
def test_edited_submissions_in_exports(self): self._publish_transportation_form() initial_count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]['count'] instance_name = 'transport_2011-07-25_19-05-36' path = _main_fixture_path(instance_name) self._make_submission(path) count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]['count'] self.assertEqual(count, initial_count + 1) # make edited submission - simulating what enketo would return instance_name = 'transport_2011-07-25_19-05-36-edited' path = _main_fixture_path(instance_name) self._make_submission(path) count = ParsedInstance.query_mongo( self.user.username, self.xform.id_string, '{}', '[]', '{}', count=True)[0]['count'] self.assertEqual(count, initial_count + 1) # create the export csv_export_url = reverse( 'csv_export', kwargs={"username": self.user.username, "id_string": self.xform.id_string}) response = self.client.get(csv_export_url) self.assertEqual(response.status_code, 200) f = StringIO.StringIO(self._get_response_content(response)) csv_reader = csv.DictReader(f) data = [row for row in csv_reader] f.close() num_rows = len(data) # number of rows == initial_count + 1 self.assertEqual(num_rows, initial_count + 1) key = 'transport/loop_over_transport_types_frequency/ambulance/'\ 'frequency_to_referral_facility' self.assertEqual(data[initial_count][key], "monthly")
def _query_mongo(self, query='{}', start=0, limit=ParsedInstance.DEFAULT_LIMIT, fields='[]', count=False): # ParsedInstance.query_mongo takes params as json strings # so we dumps the fields dictionary count_args = { 'username': self.username, 'id_string': self.id_string, 'query': query, 'fields': '[]', 'sort': '{}', 'count': True } count_object = ParsedInstance.query_mongo(**count_args) record_count = count_object[0]["count"] if record_count == 0: raise NoRecordsFoundError("No records found for your query") # if count was requested, return the count if count: return record_count else: query_args = { 'username': self.username, 'id_string': self.id_string, 'query': query, 'fields': fields, #TODO: we might want to add this in for the user #to sepcify a sort order 'sort': '{}', 'start': start, 'limit': limit, 'count': False } # use ParsedInstance.query_mongo cursor = ParsedInstance.query_mongo(**query_args) return cursor
def api(request, username=None, id_string=None): """ Returns all results as JSON. If a parameter string is passed, it takes the 'query' parameter, converts this string to a dictionary, an that is then used as a MongoDB query string. NOTE: only a specific set of operators are allow, currently $or and $and. Please send a request if you'd like another operator to be enabled. NOTE: Your query must be valid JSON, double check it here, http://json.parser.online.fr/ E.g. api?query='{"last_name": "Smith"}' """ if request.method == "OPTIONS": response = HttpResponse() add_cors_headers(response) return response helper_auth_helper(request) helper_auth_helper(request) xform, owner = check_and_set_user_and_form(username, id_string, request) if not xform: return HttpResponseForbidden(_(u"Not shared.")) try: args = { "username": username, "id_string": id_string, "query": request.GET.get("query"), "fields": request.GET.get("fields"), "sort": request.GET.get("sort"), } if "start" in request.GET: args["start"] = int(request.GET.get("start")) if "limit" in request.GET: args["limit"] = int(request.GET.get("limit")) if "count" in request.GET: args["count"] = True if int(request.GET.get("count")) > 0 else False cursor = ParsedInstance.query_mongo(**args) except ValueError, e: return HttpResponseBadRequest(e.__str__())
def test_owner_can_delete(self): #Test if Form owner can delete #check record exist before delete and after delete count = Instance.objects.filter(deleted_at=None).count() instance = Instance.objects.filter( xform=self.xform).latest('date_created') self.assertEqual(instance.deleted_at, None) # delete params = {'id': instance.id} response = self.client.post(self.delete_url, params) self.assertEqual(response.status_code, 200) self.assertEqual( Instance.objects.filter(deleted_at=None).count(), count - 1) instance = Instance.objects.get(id=instance.id) self.assertTrue(isinstance(instance.deleted_at, datetime)) self.assertNotEqual(instance.deleted_at, None) query = '{"_id": %s}' % instance.id self.mongo_args.update({"query": query}) #check that query_mongo will not return the deleted record after = ParsedInstance.query_mongo(**self.mongo_args) self.assertEqual(len(after), count - 1)
def test_owner_can_delete(self): # Test if Form owner can delete # check record exist before delete and after delete count = Instance.objects.filter(deleted_at=None).count() instance = Instance.objects.filter( xform=self.xform).latest('date_created') self.assertEqual(instance.deleted_at, None) # delete params = {'id': instance.id} response = self.client.post(self.delete_url, params) self.assertEqual(response.status_code, 200) self.assertEqual( Instance.objects.filter(deleted_at=None).count(), count - 1) instance = Instance.objects.get(id=instance.id) self.assertTrue(isinstance(instance.deleted_at, datetime)) self.assertNotEqual(instance.deleted_at, None) query = '{"_id": %s}' % instance.id self.mongo_args.update({"query": query}) # check that query_mongo will not return the deleted record after = ParsedInstance.query_mongo(**self.mongo_args) self.assertEqual(len(after), count - 1)
def _get_data(self): cursor = ParsedInstance.query_mongo(**self.mongo_args) records = list(record for record in cursor) return records
def test_edited_submission_require_auth(self): """ Test submissions that have been edited """ xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml" ) # require authentication self.user.profile.require_auth = True self.user.profile.save() num_instances_history = InstanceHistory.objects.count() num_instances = Instance.objects.count() query_args = { 'username': self.user.username, 'id_string': self.xform.id_string, 'query': '{}', 'fields': '[]', 'sort': '[]', 'count': True } cursor = ParsedInstance.query_mongo(**query_args) num_mongo_instances = cursor[0]['count'] # make first submission self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) self.assertEqual(Instance.objects.count(), num_instances + 1) # no new record in instances history self.assertEqual( InstanceHistory.objects.count(), num_instances_history) # check count of mongo instances after first submission cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # create a new user alice = self._create_user('alice', 'alice') UserProfile.objects.create(user=alice) auth = DigestAuth('alice', 'alice') # edited submission xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml" ) self._make_submission(xml_submission_file_path, auth=auth) self.assertEqual(self.response.status_code, 403) # assign report perms to user assign_perm('report_xform', alice, self.xform) assign_perm('logger.change_xform', alice, self.xform) self._make_submission(xml_submission_file_path, auth=auth) self.assertEqual(self.response.status_code, 201) # we must have the same number of instances self.assertEqual(Instance.objects.count(), num_instances + 1) # should be a new record in instances history self.assertEqual( InstanceHistory.objects.count(), num_instances_history + 1) cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # make sure we edited the mongo db record and NOT added a new row query_args['count'] = False cursor = ParsedInstance.query_mongo(**query_args) record = cursor[0] with open(xml_submission_file_path, "r") as f: xml_str = f.read() xml_str = clean_and_parse_xml(xml_str).toxml() edited_name = re.match(ur"^.+?<name>(.+?)</name>", xml_str).groups()[0] self.assertEqual(record['name'], edited_name)
def test_edited_submission_require_auth(self): """ Test submissions that have been edited """ xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid.xml") # require authentication self.user.profile.require_auth = True self.user.profile.save() num_instances_history = InstanceHistory.objects.count() num_instances = Instance.objects.count() query_args = { 'username': self.user.username, 'id_string': self.xform.id_string, 'query': '{}', 'fields': '[]', 'sort': '[]', 'count': True } cursor = ParsedInstance.query_mongo(**query_args) num_mongo_instances = cursor[0]['count'] # make first submission self._make_submission(xml_submission_file_path) self.assertEqual(self.response.status_code, 201) self.assertEqual(Instance.objects.count(), num_instances + 1) # no new record in instances history self.assertEqual(InstanceHistory.objects.count(), num_instances_history) # check count of mongo instances after first submission cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # create a new user alice = self._create_user('alice', 'alice') UserProfile.objects.create(user=alice) auth = DigestAuth('alice', 'alice') # edited submission xml_submission_file_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml") self._make_submission(xml_submission_file_path, auth=auth) self.assertEqual(self.response.status_code, 403) # assign report perms to user assign_perm('report_xform', alice, self.xform) assign_perm('logger.change_xform', alice, self.xform) self._make_submission(xml_submission_file_path, auth=auth) self.assertEqual(self.response.status_code, 201) # we must have the same number of instances self.assertEqual(Instance.objects.count(), num_instances + 1) # should be a new record in instances history self.assertEqual(InstanceHistory.objects.count(), num_instances_history + 1) cursor = ParsedInstance.query_mongo(**query_args) self.assertEqual(cursor[0]['count'], num_mongo_instances + 1) # make sure we edited the mongo db record and NOT added a new row query_args['count'] = False cursor = ParsedInstance.query_mongo(**query_args) record = cursor[0] with open(xml_submission_file_path, "r") as f: xml_str = f.read() xml_str = clean_and_parse_xml(xml_str).toxml() edited_name = re.match(r"^.+?<name>(.+?)</name>", xml_str).groups()[0] self.assertEqual(record['name'], edited_name)