""" Django views for intake-related endpoints. """ import json import logging from django.conf import settings from django.http import HttpRequest, HttpResponse, JsonResponse from django.views.decorators.csrf import csrf_exempt from access_core.intake import handlers from access_core.services.healthie_webhook import ( WebhookPayload, WebhookSignatureError, parse_webhook, ) logger = logging.getLogger(__name__) # ------------------------------------------------------------------ # Webhook endpoint # ------------------------------------------------------------------ @csrf_exempt def healthie_webhook(request: HttpRequest) -> HttpResponse: """ Receive Healthie webhook events. Healthie sends lightweight pointer payloads: { "resource_id": "12345", "resource_id_type": "FormAnswerGroup", "event_type": "form_answer_group.created", "changed_fields": [] } For create/delete events, no data is sent — we must fetch via GraphQL. For update events, changed_fields lists the modified fields. """ if request.method != "POST": return HttpResponse("Method not allowed", status=405) # Verify signature (skip if disabled in dev) verify_signature = getattr(settings, "HEALTHIE_WEBHOOK_VERIFY_SIGNATURE", True) try: if verify_signature: payload = parse_webhook(request) else: body = json.loads(request.body) payload = WebhookPayload( resource_id=str(body.get("resource_id", "")), resource_id_type=body.get("resource_id_type", ""), event_type=body.get("event_type", ""), changed_fields=body.get("changed_fields", []), raw_body=body, ) except WebhookSignatureError as e: logger.error(f"Webhook signature verification failed: {e}") return JsonResponse({"error": "Invalid signature"}, status=401) except json.JSONDecodeError as e: logger.error(f"Webhook body is not valid JSON: {e}") return JsonResponse({"error": "Invalid JSON"}, status=400) except Exception: logger.exception("Unhandled webhook verification error") return JsonResponse({"error": "Internal server error"}, status=500) event_type = payload.event_type handler_fn = handlers.get_handler(event_type) if not handler_fn: logger.warning(f"No handler registered for event: {event_type}") # Still store raw payload for debugging from access_core.intake.models import RawIngestionRecord RawIngestionRecord.objects.create( source_system="healthie", source_record_id=payload.resource_id, raw_payload=payload.raw_body, processing_status="received", ) return HttpResponse("OK", status=200) try: result = handler_fn(payload) logger.info( f"Webhook processed: {event_type} resource={payload.resource_id} -> {result}" ) except Exception: logger.exception(f"Webhook handler failed for {event_type}") # Return 500 to trigger Healthie retry logic return JsonResponse({"error": "Processing failed"}, status=500) return HttpResponse("OK", status=200)