From 45d0f180fe34dc05216253b66bf20be823a4b072 Mon Sep 17 00:00:00 2001 From: dekzter Date: Sun, 15 Feb 2026 07:36:08 -0500 Subject: [PATCH] added endpoint for testing connections with a dummy payload --- apps/connect/api_views.py | 67 +++++++++++++++++++++++++++++++++++-- apps/connect/serializers.py | 22 ++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/apps/connect/api_views.py b/apps/connect/api_views.py index 1402de04..de3903c0 100644 --- a/apps/connect/api_views.py +++ b/apps/connect/api_views.py @@ -3,6 +3,7 @@ from rest_framework.pagination import PageNumberPagination from django_filters.rest_framework import DjangoFilterBackend from rest_framework.response import Response from rest_framework.decorators import action +from django.utils import timezone from .models import Integration, EventSubscription, DeliveryLog from .serializers import ( IntegrationSerializer, @@ -12,7 +13,10 @@ from .serializers import ( from apps.accounts.permissions import ( Authenticated, permission_classes_by_action, + IsAdmin, ) +from .handlers.webhook import WebhookHandler +from .handlers.script import ScriptHandler class IntegrationViewSet(viewsets.ModelViewSet): @@ -21,9 +25,11 @@ class IntegrationViewSet(viewsets.ModelViewSet): def get_permissions(self): try: - return [perm() for perm in permission_classes_by_action[self.action]] + perms = permission_classes_by_action[self.action] except KeyError: - return [Authenticated()] + # Respect view/action-specific permission_classes if provided; fallback to Authenticated + perms = getattr(self, "permission_classes", [Authenticated]) + return [perm() for perm in perms] @action(detail=True, methods=["get"], url_path="subscriptions") def list_subscriptions(self, request, pk=None): @@ -99,6 +105,63 @@ class IntegrationViewSet(viewsets.ModelViewSet): serializer = EventSubscriptionSerializer(updated, many=True) return Response(serializer.data, status=status.HTTP_200_OK) + @action(detail=True, methods=["post"], url_path="test", permission_classes=[IsAdmin]) + def test(self, request, pk=None): + """ + Execute a saved integration (connect) with a dummy payload to verify configuration. + """ + try: + integration = Integration.objects.get(pk=pk) + except Integration.DoesNotExist: + return Response({"detail": "Integration not found"}, status=status.HTTP_404_NOT_FOUND) + + # Build a dummy payload similar to system events + now = timezone.now().isoformat() + dummy_payload = { + "event": "test", + "timestamp": now, + "channel_name": "Test Channel", + "stream_name": "Test Stream", + "stream_url": "http://example.com/stream.m3u8", + "channel_url": "http://example.com/stream.m3u8", + "provider_name": "Test Provider", + "profile_used": "Default", + "test": True, + } + + # Choose handler based on saved type + if integration.type == "webhook": + handler = WebhookHandler(integration, None, dummy_payload) + elif integration.type == "script": + handler = ScriptHandler(integration, None, dummy_payload) + else: + return Response( + {"success": False, "error": f"Unsupported integration type: {integration.type}"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + try: + result = handler.execute() + return Response( + { + "success": bool(result.get("success")), + "type": integration.type, + "request_payload": dummy_payload, + "result": result, + }, + status=status.HTTP_200_OK, + ) + except Exception as e: + return Response( + { + "success": False, + "type": integration.type, + "request_payload": dummy_payload, + "error": str(e), + }, + status=status.HTTP_502_BAD_GATEWAY, + ) + class EventSubscriptionViewSet(viewsets.ModelViewSet): queryset = EventSubscription.objects.all() diff --git a/apps/connect/serializers.py b/apps/connect/serializers.py index 859295f3..832fc14b 100644 --- a/apps/connect/serializers.py +++ b/apps/connect/serializers.py @@ -1,5 +1,6 @@ from rest_framework import serializers from .models import Integration, EventSubscription, DeliveryLog +import os class EventSubscriptionSerializer(serializers.ModelSerializer): @@ -29,6 +30,27 @@ class IntegrationSerializer(serializers.ModelSerializer): "subscriptions", ] + def validate(self, attrs): + type = attrs.get("type") if "type" in attrs else getattr(self.instance, "type", None) + config = attrs.get("config") if "config" in attrs else getattr(self.instance, "config", {}) + + if type == "script": + path = (config or {}).get("path") + if not path or not isinstance(path, str): + raise serializers.ValidationError({"config": "Script config must include a 'path' string"}) + + real_path = os.path.abspath(os.path.realpath(path)) + if not os.path.exists(real_path): + raise serializers.ValidationError({"config": f"Script path does not exist: {path}"}) + elif type == "webhook": + url = (config or {}).get("url") + if not url or not isinstance(url, str): + raise serializers.ValidationError({"config": "Webhook config must include a 'url' string"}) + else: + raise serializers.ValidationError({"type": "Unsupported integration type"}) + + return attrs + class DeliveryLogSerializer(serializers.ModelSerializer): subscription = EventSubscriptionSerializer(read_only=True)