Skip to content

Commit

Permalink
Merge pull request #1526 Exposes submissions url to enketo
Browse files Browse the repository at this point in the history
  • Loading branch information
ukanga committed Mar 11, 2019
2 parents 7941f71 + d607c11 commit 9f57942
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 102 deletions.
27 changes: 27 additions & 0 deletions docs/forms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,33 @@ Response
"enketo_preview_url": "https://H6Ic6.enketo.org/webform/preview?server=https://api.ona.io/geoffreymuchai/&id=form_id"
}

Get single submission url
-------------------------
.. raw:: html

<pre class="prettyprint">
<b>GET</b> /api/v1/forms/<code>{pk}</code>/enketo?survey_type=single</pre>

Request
^^^^^^^
::

curl -X GET https://api.ona.io/api/v1/forms/28058/enketo?survey_type=single

Response
^^^^^^^^
::

HTTP 200 OK

Response
^^^^^^^^^
::

{
"single_submit_url": "https://enke.to/single/::abcd"
}


Get form data in xls, csv format.
---------------------------------
Expand Down
14 changes: 13 additions & 1 deletion onadata/apps/api/tests/mocked_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import json

import requests
from httmock import urlmatch
from httmock import urlmatch, all_requests


@urlmatch(netloc=r'(.*\.)?ona\.io$', path=r'^/examples/forms/tutorial/form$')
Expand Down Expand Up @@ -77,6 +77,18 @@ def enketo_mock(url, request): # pylint: disable=unused-argument
return response


@all_requests
def enketo_single_submission_mock(url, request):
"""Return mocked enketo single submission Response object."""
response = requests.Response()
response.status_code = 200
# pylint: disable=protected-access
response._content = \
'{\n "single_url": "https:\\/\\/enketo.ona.io\\/single/::XZqoZ94y",\n'\
' "code": "200"\n}'
return response


@urlmatch(netloc=r'(.*\.)?enketo\.ona\.io$', path=r'^/api_v1/survey/preview$')
def enketo_preview_url_mock(url, request): # pylint: disable=unused-argument
"""
Expand Down
25 changes: 22 additions & 3 deletions onadata/apps/api/tests/viewsets/test_xform_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import json
import os
import re
from builtins import open
from collections import OrderedDict
from datetime import datetime
from datetime import timedelta
Expand All @@ -17,7 +18,6 @@
from xml.dom import minidom

import jwt
from builtins import open
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
Expand All @@ -39,7 +39,8 @@
enketo_url_mock, external_mock, external_mock_single_instance,
external_mock_single_instance2, xls_url_no_extension_mock,
xls_url_no_extension_mock_content_disposition_attr_jumbled_v1,
xls_url_no_extension_mock_content_disposition_attr_jumbled_v2)
xls_url_no_extension_mock_content_disposition_attr_jumbled_v2,
enketo_single_submission_mock)
from onadata.apps.api.tests.viewsets.test_abstract_viewset import \
TestAbstractViewSet
from onadata.apps.api.viewsets.project_viewset import ProjectViewSet
Expand Down Expand Up @@ -732,8 +733,11 @@ def test_enketo_url_error502(self):
response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.data, data)

@override_settings(TESTING_MODE=False)
def test_enketo_url(self):
with HTTMock(enketo_preview_url_mock, enketo_url_mock):
"""Test functionality to expose enketo urls."""
with HTTMock(enketo_preview_url_mock, enketo_url_mock,
enketo_single_submission_mock):
self._publish_xls_form_to_project()
view = XFormViewSet.as_view({
'get': 'enketo'
Expand All @@ -747,6 +751,21 @@ def test_enketo_url(self):
data = {"enketo_url": url, "enketo_preview_url": preview_url}
self.assertEqual(response.data, data)

def test_get_single_submit_url(self):
with HTTMock(enketo_preview_url_mock, enketo_url_mock,
enketo_single_submission_mock):
self._publish_xls_form_to_project()
view = XFormViewSet.as_view({
'get': 'enketo'
})
formid = self.xform.pk
get_data = {'survey_type': 'single'}
request = self.factory.get('/', data=get_data, **self.extra)
response = view(request, pk=formid)
submit_url = "https://enketo.ona.io/single/::XZqoZ94y"
data = {"single_submit_url": submit_url}
self.assertEqual(response.data, data)

def test_enketo_url_with_default_form_params(self):
with HTTMock(enketo_preview_url_mock, enketo_mock_with_form_defaults):
self._publish_xls_form_to_project()
Expand Down
19 changes: 15 additions & 4 deletions onadata/apps/api/viewsets/xform_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
from onadata.libs.utils.viewer_tools import (enketo_url,
generate_enketo_form_defaults,
get_enketo_preview_url,
get_form_url)
get_form_url,
get_enketo_single_submit_url)
from onadata.libs.exceptions import EnketoError
from onadata.settings.common import XLS_EXTENSIONS, CSV_EXTENSION

Expand Down Expand Up @@ -387,6 +388,9 @@ def login(self, request, **kwargs):

@action(methods=['GET'], detail=True)
def enketo(self, request, **kwargs):
"""Expose enketo urls."""
survey_type = self.kwargs.get('survey_type') or \
request.GET.get('survey_type')
self.object = self.get_object()
form_url = get_form_url(
request, self.object.user.username, settings.ENKETO_PROTOCOL,
Expand All @@ -400,17 +404,24 @@ def enketo(self, request, **kwargs):
request_vars = request.GET
defaults = generate_enketo_form_defaults(
self.object, **request_vars)
url = enketo_url(form_url, self.object.id_string, **defaults)
url = enketo_url(
form_url, self.object.id_string, **defaults)
preview_url = get_enketo_preview_url(request,
self.object.user.username,
self.object.id_string,
xform_pk=self.object.pk)
except EnketoError as e:
data = {'message': _(u"Enketo error: %s" % e)}
else:
if url and preview_url:
if survey_type == 'single':
single_submit_url = get_enketo_single_submit_url(
request, self.object.user.username, self.object.id_string,
xform_pk=self.object.pk)
data = {"single_submit_url": single_submit_url}
elif url and preview_url:
http_status = status.HTTP_200_OK
data = {"enketo_url": url, "enketo_preview_url": preview_url}
data = {"enketo_url": url,
"enketo_preview_url": preview_url}

return Response(data, http_status)

Expand Down
103 changes: 70 additions & 33 deletions onadata/libs/tests/utils/test_viewer_tools.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,39 @@
# -*- coding: utf-8 -*-
"""
Test onadata.libs.utils.viewer_tools
"""
"""Test onadata.libs.utils.viewer_tools."""
import os
from mock import patch

import requests_mock
from django.conf import settings
from django.core.files.base import File
from django.http import Http404
from django.test.client import RequestFactory
from django.test.utils import override_settings
from django.utils import timezone
from mock import patch

from onadata.apps.logger.models import XForm, Instance, Attachment
from onadata.apps.main.tests.test_base import TestBase
from onadata.libs.utils.viewer_tools import (export_def_from_filename,
from onadata.libs.exceptions import EnketoError
from onadata.libs.utils.viewer_tools import (create_attachments_zipfile,
export_def_from_filename,
generate_enketo_form_defaults,
get_client_ip, get_form,
get_form_url,
create_attachments_zipfile)
get_enketo_single_submit_url)


class TestViewerTools(TestBase):
"""
Test viewer_tools functions
"""
"""Test viewer_tools functions."""

def test_export_def_from_filename(self):
"""
Test export_def_from_filename().
"""
"""Test export_def_from_filename()."""
filename = "path/filename.xlsx"
ext, mime_type = export_def_from_filename(filename)
self.assertEqual(ext, 'xlsx')
self.assertEqual(mime_type, 'vnd.openxmlformats')

def test_get_client_ip(self):
"""
Test get_client_ip().
"""
"""Test get_client_ip()."""
request = RequestFactory().get("/")
client_ip = get_client_ip(request)
self.assertIsNotNone(client_ip)
Expand All @@ -45,9 +42,7 @@ def test_get_client_ip(self):

# pylint: disable=C0103
def test_get_enketo_defaults_without_vars(self):
"""
Test generate_enketo_form_defaults() without vars.
"""
"""Test generate_enketo_form_defaults() without vars."""
# create xform
self._publish_transportation_form()
# create map without variables
Expand All @@ -58,9 +53,7 @@ def test_get_enketo_defaults_without_vars(self):

# pylint: disable=C0103
def test_get_enketo_defaults_with_right_xform(self):
"""
Test generate_enketo_form_defaults() with xform vars.
"""
"""Test generate_enketo_form_defaults() with xform vars."""
# create xform
self._publish_transportation_form()
# create kwargs with existing xform variable
Expand All @@ -76,9 +69,7 @@ def test_get_enketo_defaults_with_right_xform(self):

# pylint: disable=C0103
def test_get_enketo_defaults_with_multiple_params(self):
"""
Test generate_enketo_form_defaults() with multiple params
"""
"""Test generate_enketo_form_defaults() with multiple params."""
# create xform
self._publish_transportation_form()
# create kwargs with existing xform variable
Expand Down Expand Up @@ -106,9 +97,7 @@ def test_get_enketo_defaults_with_multiple_params(self):

# pylint: disable=C0103
def test_get_enketo_defaults_with_non_existent_field(self):
"""
Test generate_enketo_form_defaults() with non existent field.
"""
"""Test generate_enketo_form_defaults() with non existent field."""
# create xform
self._publish_transportation_form()
# create kwargs with NON-existing xform variable
Expand All @@ -117,9 +106,7 @@ def test_get_enketo_defaults_with_non_existent_field(self):
self.assertEqual(defaults, {})

def test_get_form(self):
"""
Test get_form().
"""
"""Test get_form()."""
# non existent id_string
with self.assertRaises(Http404):
get_form({'id_string': 'non_existent_form'})
Expand All @@ -144,9 +131,7 @@ def test_get_form(self):

@override_settings(TESTING_MODE=False)
def test_get_form_url(self):
"""
Test get_form_url()
"""
"""Test get_form_url()."""
request = RequestFactory().get('/')

# default https://ona.io
Expand Down Expand Up @@ -193,3 +178,55 @@ def test_create_attachments_zipfile_file_too_big(self, rpt_mock):

self.assertTrue(rpt_mock.called)
rpt_mock.assert_called_with(message[0], message[1])

@override_settings(TESTING_MODE=False)
def test_get_submissions_url(self):
"""Test get_submissions_url()."""
@override_settings(TESTING_MODE=False, ENKETO_URL='https://enketo.ona.io')
@requests_mock.Mocker()
def test_get_enketo_single_submit_url(self, mocked):
"""Test get_single_submit_url.
Ensures single submit url is being received.
"""
request = RequestFactory().get('/')

mocked_response = {
"single_url": "https://enketo.ona.io/single/::XZqoZ94y",
"code": 200
}

enketo_url = settings.ENKETO_URL + "/api/v2/survey/single/once"
username = "bob"
server_url = get_form_url(
request, username, settings.ENKETO_PROTOCOL, True, xform_pk=1)

url = '{}?server_url={}&form_id={}'.format(
enketo_url, server_url, "tag_team")
mocked.get(url, json=mocked_response)
response = get_enketo_single_submit_url(
request, username, id_string="tag_team", xform_pk=1)

self.assertEqual(
response, 'https://enketo.ona.io/single/::XZqoZ94y')

@override_settings(TESTING_MODE=False, ENKETO_URL='https://enketo.ona.io')
@requests_mock.Mocker()
def test_get_single_submit_url_error_action(self, mocked):
"""Test get_single_submit_url to raises EnketoError."""
request = RequestFactory().get('/')

enketo_url = settings.ENKETO_URL + "/api/v2/survey/single/once"
username = "Milly"
server_url = get_form_url(
request, username, settings.ENKETO_PROTOCOL, True, xform_pk=1)

url = '{}?server_url={}&form_id={}'.format(
enketo_url, server_url, "tag_team")
mocked.get(url, status_code=401)
msg = "There was a problem with your submissionor form."\
" Please contact support."
self.assertRaisesMessage(
EnketoError,
msg, get_enketo_single_submit_url,
request, username, "tag_team", 1)
Loading

0 comments on commit 9f57942

Please sign in to comment.