Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Tableau Documentation #1989

Merged
merged 2 commits into from
Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ Flow Results Packages

flow-results

Onadata-Tableau Intergration
------------------------------

.. toctree::
:maxdepth: 2

onadata-tableau

Ona Tagging API
~~~~~~~~~~~~~~~

Expand Down
270 changes: 270 additions & 0 deletions docs/onadata-tableau.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
Onadata-Tableau
***************

Visualize data collected with the onadata application on |Tableau|. This endpoint provides access to submitted data being pushed to Tableau via the Web Data Connector in JSON format.

.. |Tableau| raw:: html

<a href="https://www.tableau.com/"
target="_blank">Tableau</a>


Where:

- ``uuid`` - the form open data unique identifier


Tableau Web Data Connector Endpoints
------------------------------------

Schema Endpoint Example
^^^^^^^^^^^^^^^^^^^^^^^
::

curl -X GET /api/v2/open-data/24fde84caec342a19a7f2e3ea0c36e3f/schema

Response
^^^^^^^^
::

[
{
"table_alias": "data",
"connection_name": "22_test",
"column_headers": [
{
"id": "_id",
"dataType": "int",
"alias": "_id"
},
{
"id": "country",
"dataType": "string",
"alias": "country"
},
{
"id": "note",
"dataType": "string",
"alias": "note"
},
{
"id": "user_select",
"dataType": "string",
"alias": "user_select"
},
{
"id": "photo",
"dataType": "string",
"alias": "photo"
},
{
"id": "meta_instanceID",
"dataType": "string",
"alias": "meta_instanceID"
}
]
}
]

Forms with nested repeats will generate multiple table schemas for Tableau

Response
^^^^^^^^
::

[
{
"table_alias": "data",
"connection_name": "22_transportation_new_form",
"column_headers": [
{
"id": "_id",
"dataType": "int",
"alias": "_id"
},
{
"id": "hospital_name",
"dataType": "string",
"alias": "hospital_name"
},
{
"id": "hospital_hiv_medication_food_cake",
"dataType": "string",
"alias": "hospital_hiv_medication_food_cake"
},
{
"id": "hospital_hiv_medication_food_cheese",
"dataType": "string",
"alias": "hospital_hiv_medication_food_cheese"
},
{
"id": "hospital_hiv_medication_food_ham",
"dataType": "string",
"alias": "hospital_hiv_medication_food_ham"
},
{
"id": "hospital_hiv_medication_food_vegetables",
"dataType": "string",
"alias": "hospital_hiv_medication_food_vegetables"
},
{
"id": "hospital_hiv_medication_have_hiv_medication",
"dataType": "string",
"alias": "hospital_hiv_medication_have_hiv_medication"
},
{
"id": "hospital_hiv_medication__gps_latitude",
"dataType": "string",
"alias": "hospital_hiv_medication__gps_latitude"
},
{
"id": "hospital_hiv_medication__gps_longitude",
"dataType": "string",
"alias": "hospital_hiv_medication__gps_longitude"
},
{
"id": "hospital_hiv_medication__gps_altitude",
"dataType": "string",
"alias": "hospital_hiv_medication__gps_altitude"
},
{
"id": "hospital_hiv_medication__gps_precision",
"dataType": "string",
"alias": "hospital_hiv_medication__gps_precision"
},
{
"id": "meta_instanceID",
"dataType": "string",
"alias": "meta_instanceID"
}
]
},
{
"table_alias": "person_repeat",
"connection_name": "22_transportation_new_form_person_repeat",
"column_headers": [
{
"id": "_id",
"dataType": "int",
"alias": "_id"
},
{
"id": "__parent_id",
"dataType": "int",
"alias": "__parent_id"
},
{
"id": "__parent_table",
"dataType": "string",
"alias": "__parent_table"
},
{
"id": "hospital_hiv_medication_person_first_name",
"dataType": "string",
"alias": "hospital_hiv_medication_person_first_name"
},
{
"id": "hospital_hiv_medication_person_last_name",
"dataType": "string",
"alias": "hospital_hiv_medication_person_last_name"
},
{
"id": "hospital_hiv_medication_person_food_cake",
"dataType": "string",
"alias": "hospital_hiv_medication_person_food_cake"
},
{
"id": "hospital_hiv_medication_person_food_cheese",
"dataType": "string",
"alias": "hospital_hiv_medication_person_food_cheese"
},
{
"id": "hospital_hiv_medication_person_food_ham",
"dataType": "string",
"alias": "hospital_hiv_medication_person_food_ham"
},
{
"id": "hospital_hiv_medication_person_food_vegetables",
"dataType": "string",
"alias": "hospital_hiv_medication_person_food_vegetables"
},
{
"id": "hospital_hiv_medication_person_have_hiv_medication",
"dataType": "string",
"alias": "hospital_hiv_medication_person_have_hiv_medication"
},
{
"id": "hospital_hiv_medication_person_age",
"dataType": "int",
"alias": "hospital_hiv_medication_person_age"
},
{
"id": "hospital_hiv_medication_person__gps_latitude",
"dataType": "string",
"alias": "hospital_hiv_medication_person__gps_latitude"
},
{
"id": "hospital_hiv_medication_person__gps_longitude",
"dataType": "string",
"alias": "hospital_hiv_medication_person__gps_longitude"
},
{
"id": "hospital_hiv_medication_person__gps_altitude",
"dataType": "string",
"alias": "hospital_hiv_medication_person__gps_altitude"
},
{
"id": "hospital_hiv_medication_person__gps_precision",
"dataType": "string",
"alias": "hospital_hiv_medication_person__gps_precision"
}
]
}
]


Data Endpoint Example
^^^^^^^^^^^^^^^^^^^^^
::

curl -X GET /api/v2/open-data/5d3da685cbe64fc6b97a1b03ffccd847/data

Response
^^^^^^^^
::

[
{
"_id": 4,
"hospital_name": "Melkizedek",
"meta_instanceID": "uuid:f0be8145-b840-4fde-a531-a38aeb1260f4",
"hospital_hiv_medication__gps_latitude": "-1.302025",
"hospital_hiv_medication__gps_longitude": "36.745877",
"hospital_hiv_medication__gps_altitude": "0",
"hospital_hiv_medication__gps_precision": "0",
"hospital_hiv_medication_food_cake": "TRUE",
"hospital_hiv_medication_food_cheese": "TRUE",
"hospital_hiv_medication_food_ham": "TRUE",
"hospital_hiv_medication_food_vegetables": "TRUE",
"person_repeat": [
{
"__parent_id": 4,
"__parent_table": "data",
"_id": 16,
"hospital_hiv_medication_person_age": 43,
"hospital_hiv_medication_person__gps_latitude": "-1.302819",
"hospital_hiv_medication_person__gps_longitude": "36.746857",
"hospital_hiv_medication_person__gps_altitude": "0",
"hospital_hiv_medication_person__gps_precision": "0",
"hospital_hiv_medication_person_food_cake": "TRUE",
"hospital_hiv_medication_person_food_cheese": "TRUE",
"hospital_hiv_medication_person_food_ham": "TRUE",
"hospital_hiv_medication_person_food_vegetables": "TRUE",
"hospital_hiv_medication_person_last_name": "Kendrik",
"hospital_hiv_medication_person_first_name": "Tom",
"hospital_hiv_medication_person_have_hiv_medication": "no"
}
],
"hospital_hiv_medication_have_hiv_medication": "yes"
}
]
24 changes: 19 additions & 5 deletions onadata/apps/api/tests/viewsets/test_ona_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@
from onadata.apps.api.tests.viewsets.test_abstract_viewset import \
TestAbstractViewSet

from onadata.apps.api.urls import router
from onadata.apps.api.urls.v1_urls import router as v1_router
from onadata.apps.api.urls.v2_urls import router as v2_router


class TestOnaApi(TestAbstractViewSet):

def test_number_of_viewsets(self):
def test_number_of_v1_viewsets(self):
'''
Counts the number of viewsets
Counts the number of v1 viewsets
for the api django app
'''
view = router.get_api_root_view()
view = v1_router.get_api_root_view()
path = '/api/v1/'
request = self.factory.get(path)
request.resolver_match = resolve(path)
response = view(request)
self.assertEquals(len(response.data), 30)
self.assertEquals(len(response.data), 29)

def test_number_of_v2_viewsets(self):
'''
Counts the number of v2 viewsets
for the api django app
'''
view = v2_router.get_api_root_view()
path = '/api/v2/'
request = self.factory.get(path)
request.resolver_match = resolve(path)
response = view(request)
self.assertEquals(len(response.data), 1)
23 changes: 20 additions & 3 deletions onadata/apps/api/tests/viewsets/test_tableau_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"""
import os
import json

from re import search
from django.test import RequestFactory
from django.utils.dateparse import parse_datetime
from onadata.apps.main.tests.test_base import TestBase
from onadata.apps.logger.models.open_data import get_or_create_opendata
from onadata.apps.api.viewsets.tableau_viewset import (
from onadata.apps.api.viewsets.v2.tableau_viewset import (
TableauViewSet, unpack_select_multiple_data,
unpack_gps_data)
unpack_gps_data, clean_xform_headers)
from onadata.libs.renderers.renderers import pairing


Expand Down Expand Up @@ -299,3 +299,20 @@ def test_unpack_gps_data(self):
'_gps_precision': '0'
}
self.assertEqual(data, expected_data)

def test_clean_xform_headers(self):
"""
Test that column header fields for group columns
do not contain indexing when schema columns
are being pushed to Tableau.
"""
headers = self.xform.get_headers(repeat_iterations=1)
group_columns = [
field for field in headers if search(r"\[+\d+\]", field)]
self.assertEqual(group_columns,
['children[1]/childs_name',
'children[1]/childs_age'])

cleaned_data = clean_xform_headers(group_columns)
self.assertEqual(cleaned_data,
['childs_name', 'childs_age'])
Empty file.
2 changes: 0 additions & 2 deletions onadata/apps/api/urls.py → onadata/apps/api/urls/v1_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from onadata.apps.api.viewsets.metadata_viewset import MetaDataViewSet
from onadata.apps.api.viewsets.note_viewset import NoteViewSet
from onadata.apps.api.viewsets.open_data_viewset import OpenDataViewSet
from onadata.apps.api.viewsets.tableau_viewset import TableauViewSet
from onadata.apps.api.viewsets.organization_profile_viewset import \
OrganizationProfileViewSet
from onadata.apps.api.viewsets.osm_viewset import OsmViewSet
Expand Down Expand Up @@ -134,7 +133,6 @@ def get_urls(self):
router.register(r'metadata', MetaDataViewSet, basename='metadata')
router.register(r'notes', NoteViewSet)
router.register(r'open-data', OpenDataViewSet, basename='open-data')
router.register(r'open-data-v2', TableauViewSet, basename='open-data-v2')
router.register(r'orgs', OrganizationProfileViewSet)
router.register(r'osm', OsmViewSet, basename='osm')
router.register(
Expand Down
9 changes: 9 additions & 0 deletions onadata/apps/api/urls/v2_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding=utf-8 -*-
"""
Custom rest_framework Router V2
"""
from .v1_urls import MultiLookupRouter
from onadata.apps.api.viewsets.v2.tableau_viewset import TableauViewSet

router = MultiLookupRouter(trailing_slash=False)
router.register(r'open-data', TableauViewSet, basename='open-data')
Empty file.
Loading