Skip to content

Commit

Permalink
Add RapidProJSONSubmissionSerializer
Browse files Browse the repository at this point in the history
Add RapidProJSONSubmissionSerializer; A serializer meant to handle JSON
webhook post requests from RapidPro
  • Loading branch information
DavisRayM committed Apr 6, 2020
1 parent 29d6984 commit 093a44c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 4 deletions.
37 changes: 37 additions & 0 deletions onadata/apps/api/tests/viewsets/test_xform_submission_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,43 @@ def test_rapidpro_post_submission(self):
Test a Rapidpro Webhook POST submission.
"""
# pylint: disable=C0301
data = json.dumps({
'contact': {
'name': 'Davis',
'urn': 'tel:+12065551212',
'uuid': '23dae14f-7202-4ff5-bdb6-2390d2769968'
},
'flow': {
'name': '1166',
'uuid': '9da5e439-35af-4ecb-b7fc-2911659f6b04'
},
'results': {
'fruit_name': {
'category': 'All Responses',
'value': 'orange'
},
}
})

request = self.factory.post(
'/submission', data,
content_type='application/json',
HTTP_USER_AGENT='RapidProMailroom/5.2.0')
response = self.view(request)
self.assertEqual(response.status_code, 401)
auth = DigestAuth('bob', 'bobbob')
request.META.update(auth(request.META, response))
response = self.view(request, username=self.user.username,
xform_pk=self.xform.pk)
self.assertContains(response, 'Successful submission', status_code=201)
self.assertTrue(response.has_header('Date'))
self.assertEqual(response['Location'], 'http://testserver/submission')

def test_legacy_rapidpro_post_submission(self):
"""
Test a Legacy Rapidpro Webhook POST submission.
"""
# pylint: disable=C0301
data = 'run=76250&text=orange&flow_uuid=9da5e439-35af-4ecb-b7fc-2911659f6b04&phone=%2B12065550100&step=3b15df81-a0bd-4de7-8186-145ea3bb6c43&contact_name=Antonate+Maritim&flow_name=fruit&header=Authorization&urn=tel%3A%2B12065550100&flow=1166&relayer=-1&contact=fe4df540-39c1-4647-b4bc-1c93833e22e0&values=%5B%7B%22category%22%3A+%7B%22base%22%3A+%22All+Responses%22%7D%2C+%22node%22%3A+%228037c12f-a277-4255-b630-6a03b035767a%22%2C+%22time%22%3A+%222017-10-04T07%3A18%3A08.171069Z%22%2C+%22text%22%3A+%22orange%22%2C+%22rule_value%22%3A+%22orange%22%2C+%22value%22%3A+%22orange%22%2C+%22label%22%3A+%22fruit_name%22%7D%5D&time=2017-10-04T07%3A18%3A08.205524Z&steps=%5B%7B%22node%22%3A+%220e18202f-9ec4-4756-b15b-e9f152122250%22%2C+%22arrived_on%22%3A+%222017-10-04T07%3A15%3A17.548657Z%22%2C+%22left_on%22%3A+%222017-10-04T07%3A15%3A17.604668Z%22%2C+%22text%22%3A+%22Fruit%3F%22%2C+%22type%22%3A+%22A%22%2C+%22value%22%3A+null%7D%2C+%7B%22node%22%3A+%228037c12f-a277-4255-b630-6a03b035767a%22%2C+%22arrived_on%22%3A+%222017-10-04T07%3A15%3A17.604668Z%22%2C+%22left_on%22%3A+%222017-10-04T07%3A18%3A08.171069Z%22%2C+%22text%22%3A+%22orange%22%2C+%22type%22%3A+%22R%22%2C+%22value%22%3A+%22orange%22%7D%2C+%7B%22node%22%3A+%223b15df81-a0bd-4de7-8186-145ea3bb6c43%22%2C+%22arrived_on%22%3A+%222017-10-04T07%3A18%3A08.171069Z%22%2C+%22left_on%22%3A+null%2C+%22text%22%3A+null%2C+%22type%22%3A+%22A%22%2C+%22value%22%3A+null%7D%5D&flow_base_language=base&channel=-1' # noqa
request = self.factory.post(
'/submission', data,
Expand Down
12 changes: 8 additions & 4 deletions onadata/apps/api/viewsets/xform_submission_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
from onadata.libs.renderers.renderers import FLOIPRenderer, TemplateXMLRenderer
from onadata.libs.serializers.data_serializer import (
FLOIPSubmissionSerializer, JSONSubmissionSerializer,
RapidProSubmissionSerializer, SubmissionSerializer)
RapidProSubmissionSerializer, SubmissionSerializer,
RapidProJSONSubmissionSerializer)
from onadata.libs.utils.logger_tools import OpenRosaResponseBadRequest

BaseViewset = get_baseviewset_class() # pylint: disable=C0103
Expand Down Expand Up @@ -83,10 +84,13 @@ def get_serializer_class(self):
content_type = self.request.content_type.lower()

if 'application/json' in content_type:
self.request.accepted_renderer = JSONRenderer()
self.request.accepted_media_type = 'application/json'
if 'RapidProMailroom' in self.request.META.get('HTTP_USER_AGENT'):
return RapidProJSONSubmissionSerializer
else:
self.request.accepted_renderer = JSONRenderer()
self.request.accepted_media_type = 'application/json'

return JSONSubmissionSerializer
return JSONSubmissionSerializer

if 'application/x-www-form-urlencoded' in content_type:
return RapidProSubmissionSerializer
Expand Down
17 changes: 17 additions & 0 deletions onadata/libs/serializers/data_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,23 @@ def create(self, validated_data):
return instance


class RapidProJSONSubmissionSerializer(BaseRapidProSubmissionSerializer):
"""
Rapidpro SubmissionSerializer - handles RapidPro JSON webhook posts
"""
def create(self, validated_data):
"""
Returns object instances based on validated data.
"""
request, username = get_request_and_username(self.context)
post_data = request.data.get('results')
instance_data_dict = {
k: post_data[k].get('value') for k in post_data.keys()}
instance = create_submission(
request, username, instance_data_dict, validated_data['id_string'])
return instance


class FLOIPListSerializer(serializers.ListSerializer):
"""
Custom ListSerializer for a FLOIP submission.
Expand Down

0 comments on commit 093a44c

Please sign in to comment.