From ea868edd2c8e541ead9c5ae2456a2315651bfdf8 Mon Sep 17 00:00:00 2001 From: Kobo Date: Wed, 8 Nov 2023 09:19:37 +0100 Subject: [PATCH 1/2] init merge antea_merge_2_023_37d From fca01d5461aa3968cade784626415e00485f7f22 Mon Sep 17 00:00:00 2001 From: Kobo Date: Fri, 19 Jan 2024 17:10:00 +0100 Subject: [PATCH 2/2] feat(restapi): allow post hook for submit, edit, delete, validation status change --- onadata/apps/api/tools.py | 8 +++++++- onadata/apps/restservice/services/kpi_hook.py | 4 +++- onadata/apps/restservice/utils.py | 6 ++++-- onadata/apps/viewer/models/parsed_instance.py | 15 ++++++++++++--- onadata/libs/utils/common_tags.py | 8 ++++++++ 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/onadata/apps/api/tools.py b/onadata/apps/api/tools.py index 4410cd6a8..d9e3a9077 100644 --- a/onadata/apps/api/tools.py +++ b/onadata/apps/api/tools.py @@ -38,6 +38,7 @@ check_and_set_form_by_id, check_and_set_form_by_id_string, ) +from onadata.libs.utils.common_tags import HOOK_EVENT DECIMAL_PRECISION = 2 @@ -158,6 +159,8 @@ def add_validation_status_to_instance( instance.validation_status = validation_status instance.save() success = instance.parsed_instance.update_mongo(asynchronous=False) + if success: + instance.parsed_instance.call_service_event(HOOK_EVENT['ON_VALIDATION_STATUS_CHANGE']) return success @@ -185,7 +188,10 @@ def get_validation_status(validation_status_uid, asset, username): def remove_validation_status_from_instance(instance): instance.validation_status = {} instance.save() - return instance.parsed_instance.update_mongo(asynchronous=False) + success = instance.parsed_instance.update_mongo(asynchronous=False) + if success: + instance.parsed_instance.call_service_event(HOOK_EVENT['ON_VALIDATION_STATUS_CHANGE']) + return success def get_media_file_response( diff --git a/onadata/apps/restservice/services/kpi_hook.py b/onadata/apps/restservice/services/kpi_hook.py index 5c1f5c7f7..e0d145521 100644 --- a/onadata/apps/restservice/services/kpi_hook.py +++ b/onadata/apps/restservice/services/kpi_hook.py @@ -6,6 +6,7 @@ from django.conf import settings from onadata.apps.restservice.RestServiceInterface import RestServiceInterface from onadata.apps.logger.models import Instance +from onadata.libs.utils.common_tags import HOOK_EVENT class ServiceDefinition(RestServiceInterface): @@ -16,7 +17,8 @@ def send(self, endpoint, data): # Will be used internally by KPI to fetch data with KoBoCatBackend post_data = { - 'submission_id': data.get('instance_id') + 'submission_id': data.get('instance_id'), + 'event': data.get('event') or HOOK_EVENT['ON_SUBMIT'] } headers = {'Content-Type': 'application/json'} diff --git a/onadata/apps/restservice/utils.py b/onadata/apps/restservice/utils.py index ceaaaa8bf..318e64c39 100644 --- a/onadata/apps/restservice/utils.py +++ b/onadata/apps/restservice/utils.py @@ -1,9 +1,10 @@ # coding: utf-8 from onadata.apps.restservice.models import RestService from onadata.apps.restservice.tasks import service_definition_task +from onadata.libs.utils.common_tags import HOOK_EVENT -def call_service(parsed_instance): +def call_service(parsed_instance, event=HOOK_EVENT['ON_SUBMIT']): # lookup service instance = parsed_instance.instance rest_services = RestService.objects.filter(xform=instance.xform) @@ -19,6 +20,7 @@ def call_service(parsed_instance): "instance_uuid": instance.uuid, "instance_id": instance.id, "xml": parsed_instance.instance.xml, - "json": parsed_instance.to_dict_for_mongo() + "json": parsed_instance.to_dict_for_mongo(), + "event": event } service_definition_task.delay(rest_service.pk, data) diff --git a/onadata/apps/viewer/models/parsed_instance.py b/onadata/apps/viewer/models/parsed_instance.py index 52da7ee60..d3d5362d5 100644 --- a/onadata/apps/viewer/models/parsed_instance.py +++ b/onadata/apps/viewer/models/parsed_instance.py @@ -24,7 +24,8 @@ TAGS, NOTES, SUBMITTED_BY, - VALIDATION_STATUS + VALIDATION_STATUS, + HOOK_EVENT ) from onadata.libs.utils.decorators import apply_form_field_names from onadata.libs.utils.model_tools import queryset_iterator @@ -304,6 +305,9 @@ def update_mongo(self, asynchronous=True): return True + def call_service_event(self, event='on_submit'): + call_service(self, event) + @staticmethod def bulk_update_validation_statuses(query, validation_status): return xform_instances.update( @@ -372,8 +376,8 @@ def save(self, asynchronous=False, *args, **kwargs): # Signal has been removed because of a race condition. # Rest Services were called before data was saved in DB. success = self.update_mongo(asynchronous) - if success and created: - call_service(self) + if success: + self.call_service_event(HOOK_EVENT['ON_SUBMIT'] if created else HOOK_EVENT['ON_EDIT']) return success def add_note(self, note): @@ -414,9 +418,14 @@ def _get_attachments_from_instance(instance): return attachments +def _send_remove_event(sender, **kwargs): + instance = kwargs.get('instance') + instance.call_service_event(HOOK_EVENT['ON_DELETE']) + def _remove_from_mongo(sender, **kwargs): instance_id = kwargs.get('instance').instance.id xform_instances.delete_one({'_id': instance_id}) +pre_delete.connect(_send_remove_event, sender=ParsedInstance) pre_delete.connect(_remove_from_mongo, sender=ParsedInstance) diff --git a/onadata/libs/utils/common_tags.py b/onadata/libs/utils/common_tags.py index cc98a8d25..85000383a 100644 --- a/onadata/libs/utils/common_tags.py +++ b/onadata/libs/utils/common_tags.py @@ -67,3 +67,11 @@ NESTED_RESERVED_ATTRIBUTES = [ VALIDATION_STATUS, ] + + +HOOK_EVENT = { + 'ON_SUBMIT': "on_submit", + 'ON_EDIT': 'on_edit', + 'ON_DELETE': 'on_delete', + 'ON_VALIDATION_STATUS_CHANGE': 'on_validation_status_change' +} \ No newline at end of file