Marwan Alwali 2780a2dc7c update
2025-09-16 15:10:57 +03:00

2396 lines
87 KiB
Python

"""
Integration app views with comprehensive CRUD operations following healthcare best practices.
"""
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib import messages
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.views.generic import (
ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView, FormView
)
from django.urls import reverse_lazy, reverse
from django.http import JsonResponse, HttpResponse
from django.db.models import Q, Count, Avg, Sum
from django.utils import timezone
from django.core.paginator import Paginator
from django.db import transaction
from datetime import datetime, timedelta, date
import json
import requests
from django.utils.translation import gettext_lazy as _
from .models import (
ExternalSystem, IntegrationEndpoint, DataMapping, IntegrationExecution,
WebhookEndpoint, WebhookExecution, IntegrationLog
)
from .forms import (
ExternalSystemForm, IntegrationEndpointForm, DataMappingForm,
WebhookEndpointForm
)
import logging
logger = logging.getLogger(__name__)
# ============================================================================
# DASHBOARD AND OVERVIEW VIEWS
# ============================================================================
class IntegrationDashboardView(LoginRequiredMixin, TemplateView):
"""
Main integration dashboard with comprehensive statistics and recent activity.
"""
template_name = 'integration/dashboard.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Basic statistics
context.update({
'total_systems': ExternalSystem.objects.filter(tenant=self.request.user.tenant).count(),
'total_endpoints': IntegrationEndpoint.objects.filter(external_system__tenant=self.request.user.tenant).count(),
'total_mappings': DataMapping.objects.filter(endpoint__external_system__tenant=self.request.user.tenant).count(),
'total_webhooks': WebhookEndpoint.objects.filter(external_system__tenant=self.request.user.tenant).count(),
})
# Recent activity
context.update({
'recent_executions': IntegrationExecution.objects.filter(
endpoint__external_system__tenant=self.request.user.tenant
).order_by('-started_at')[:10],
'recent_webhook_executions': WebhookExecution.objects.filter(
webhook__external_system__tenant=self.request.user.tenant
).order_by('-processed_at')[:5],
'recent_logs': IntegrationLog.objects.filter(
endpoint__external_system__tenant=self.request.user.tenant
).order_by('-timestamp')[:10],
})
# Execution statistics
today = timezone.now().date()
context.update({
'executions_today': IntegrationExecution.objects.filter(
endpoint__external_system__tenant=self.request.user.tenant,
started_at__date=today
).count(),
'successful_executions': IntegrationExecution.objects.filter(
endpoint__external_system__tenant=self.request.user.tenant,
started_at__date=today,
status='SUCCESS'
).count(),
'failed_executions': IntegrationExecution.objects.filter(
endpoint__external_system__tenant=self.request.user.tenant,
started_at__date=today,
status='FAILED'
).count(),
})
# System health
context.update({
'healthy_systems': ExternalSystem.objects.filter(
tenant=self.request.user.tenant,
is_active=True,
is_healthy=True
).count(),
'unhealthy_systems': ExternalSystem.objects.filter(
tenant=self.request.user.tenant,
is_active=True,
is_healthy=False,
).count(),
})
return context
# ============================================================================
# EXTERNAL SYSTEM VIEWS (FULL CRUD - Master Data)
# ============================================================================
class ExternalSystemListView(LoginRequiredMixin, ListView):
"""
List all external systems with filtering and search capabilities.
"""
model = ExternalSystem
template_name = 'integration/external_system_list.html'
context_object_name = 'external_systems'
paginate_by = 20
def get_queryset(self):
queryset = ExternalSystem.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(system_name__icontains=search) |
Q(description__icontains=search) |
Q(base_url__icontains=search)
)
# Filter by system type
system_type = self.request.GET.get('system_type')
if system_type:
queryset = queryset.filter(system_type=system_type)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
# Filter by health status
health_status = self.request.GET.get('health_status')
if health_status:
queryset = queryset.filter(last_health_check_status=health_status)
return queryset.order_by('system_name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search'] = self.request.GET.get('search', '')
context['selected_system_type'] = self.request.GET.get('system_type', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
context['selected_health_status'] = self.request.GET.get('health_status', '')
return context
class ExternalSystemDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific external system.
"""
model = ExternalSystem
template_name = 'integration/external_system_detail.html'
context_object_name = 'external_system'
def get_queryset(self):
return ExternalSystem.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
external_system = self.get_object()
# Related endpoints
context['endpoints'] = IntegrationEndpoint.objects.filter(
external_system=external_system
).order_by('endpoint_name')
# Recent executions
context['recent_executions'] = IntegrationExecution.objects.filter(
endpoint__external_system=external_system
).order_by('-execution_time')[:10]
# Execution statistics
context['total_executions'] = IntegrationExecution.objects.filter(
endpoint__external_system=external_system
).count()
context['successful_executions'] = IntegrationExecution.objects.filter(
endpoint__external_system=external_system,
status='SUCCESS'
).count()
return context
class ExternalSystemCreateView(LoginRequiredMixin, CreateView):
"""
Create a new external system.
"""
model = ExternalSystem
form_class = ExternalSystemForm
template_name = 'integration/systems/external_system_form.html'
success_url = reverse_lazy('integration:external_system_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'External system created successfully.')
return super().form_valid(form)
class ExternalSystemUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing external system.
"""
model = ExternalSystem
form_class = ExternalSystemForm
template_name = 'integration/systems/external_system_form.html'
def get_queryset(self):
return ExternalSystem.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('integration:external_system_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'External system updated successfully.')
return super().form_valid(form)
class ExternalSystemDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete an external system.
"""
model = ExternalSystem
template_name = 'integration/systems/external_system_confirm_delete.html'
success_url = reverse_lazy('integration:external_system_list')
def get_queryset(self):
return ExternalSystem.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
external_system = self.get_object()
# Check if system has endpoints
if IntegrationEndpoint.objects.filter(external_system=external_system).exists():
messages.error(request, 'Cannot delete system that has integration endpoints.')
return redirect('integration:external_system_detail', pk=external_system.pk)
messages.success(request, f'External system {external_system.system_name} deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# INTEGRATION ENDPOINT VIEWS (FULL CRUD - Operational Data)
# ============================================================================
class IntegrationEndpointListView(LoginRequiredMixin, ListView):
"""
List all integration endpoints with filtering capabilities.
"""
model = IntegrationEndpoint
template_name = 'integration/integration_endpoint_list.html'
context_object_name = 'endpoints'
paginate_by = 20
def get_queryset(self):
queryset = IntegrationEndpoint.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(endpoint_name__icontains=search) |
Q(description__icontains=search) |
Q(endpoint_url__icontains=search)
)
# Filter by external system
external_system = self.request.GET.get('external_system')
if external_system:
queryset = queryset.filter(external_system_id=external_system)
# Filter by method
method = self.request.GET.get('method')
if method:
queryset = queryset.filter(method=method)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
return queryset.select_related('external_system').order_by('endpoint_name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['external_systems'] = ExternalSystem.objects.filter(
tenant=self.request.user.tenant
).order_by('system_name')
context['search'] = self.request.GET.get('search', '')
context['selected_external_system'] = self.request.GET.get('external_system', '')
context['selected_method'] = self.request.GET.get('method', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
return context
class IntegrationEndpointDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific integration endpoint.
"""
model = IntegrationEndpoint
template_name = 'integration/integration_endpoint_detail.html'
context_object_name = 'endpoint'
def get_queryset(self):
return IntegrationEndpoint.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
endpoint = self.get_object()
# Data mappings
context['data_mappings'] = DataMapping.objects.filter(
endpoint=endpoint
).order_by('field_name')
# Recent executions
context['recent_executions'] = IntegrationExecution.objects.filter(
endpoint=endpoint
).order_by('-execution_time')[:10]
# Execution statistics
context['total_executions'] = IntegrationExecution.objects.filter(
endpoint=endpoint
).count()
context['successful_executions'] = IntegrationExecution.objects.filter(
endpoint=endpoint,
status='SUCCESS'
).count()
return context
class IntegrationEndpointCreateView(LoginRequiredMixin, CreateView):
"""
Create a new integration endpoint.
"""
model = IntegrationEndpoint
form_class = IntegrationEndpointForm
template_name = 'integration/integration_endpoint_form.html'
success_url = reverse_lazy('integration:integration_endpoint_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'Integration endpoint created successfully.')
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class IntegrationEndpointUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing integration endpoint.
"""
model = IntegrationEndpoint
form_class = IntegrationEndpointForm
template_name = 'integration/integration_endpoint_form.html'
def get_queryset(self):
return IntegrationEndpoint.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('integration:integration_endpoint_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Integration endpoint updated successfully.')
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class IntegrationEndpointDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete an integration endpoint.
"""
model = IntegrationEndpoint
template_name = 'integration/integration_endpoint_confirm_delete.html'
success_url = reverse_lazy('integration:integration_endpoint_list')
def get_queryset(self):
return IntegrationEndpoint.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
messages.success(request, 'Integration endpoint deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# DATA MAPPING VIEWS (FULL CRUD - Operational Data)
# ============================================================================
class DataMappingListView(LoginRequiredMixin, ListView):
"""
List all data mappings with filtering capabilities.
"""
model = DataMapping
template_name = 'integration/data_mapping_list.html'
context_object_name = 'data_mappings'
paginate_by = 20
def get_queryset(self):
queryset = DataMapping.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(field_name__icontains=search) |
Q(source_field__icontains=search) |
Q(target_field__icontains=search)
)
# Filter by endpoint
endpoint = self.request.GET.get('endpoint')
if endpoint:
queryset = queryset.filter(endpoint_id=endpoint)
# Filter by direction
direction = self.request.GET.get('direction')
if direction:
queryset = queryset.filter(direction=direction)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
return queryset.select_related('endpoint').order_by('field_name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['endpoints'] = IntegrationEndpoint.objects.filter(
tenant=self.request.user.tenant
).order_by('endpoint_name')
context['search'] = self.request.GET.get('search', '')
context['selected_endpoint'] = self.request.GET.get('endpoint', '')
context['selected_direction'] = self.request.GET.get('direction', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
return context
class DataMappingDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific data mapping.
"""
model = DataMapping
template_name = 'integration/data_mapping_detail.html'
context_object_name = 'data_mapping'
def get_queryset(self):
return DataMapping.objects.filter(tenant=self.request.user.tenant)
class DataMappingCreateView(LoginRequiredMixin, CreateView):
"""
Create a new data mapping.
"""
model = DataMapping
form_class = DataMappingForm
template_name = 'integration/data_mapping_form.html'
success_url = reverse_lazy('integration:data_mapping_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'Data mapping created successfully.')
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class DataMappingUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing data mapping.
"""
model = DataMapping
form_class = DataMappingForm
template_name = 'integration/data_mapping_form.html'
def get_queryset(self):
return DataMapping.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('integration:data_mapping_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Data mapping updated successfully.')
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class DataMappingDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete a data mapping.
"""
model = DataMapping
template_name = 'integration/data_mapping_confirm_delete.html'
success_url = reverse_lazy('integration:data_mapping_list')
def get_queryset(self):
return DataMapping.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
messages.success(request, 'Data mapping deleted successfully.')
return super().delete(request, *args, **kwargs)
class IntegrationExecutionListView(LoginRequiredMixin, ListView):
"""
List all integration executions (read-only).
"""
model = IntegrationExecution
template_name = 'integration/executions/integration_execution_list.html'
context_object_name = 'executions'
paginate_by = 20
def get_queryset(self):
tenant = self.request.user.tenant
queryset = IntegrationExecution.objects.filter(endpoint__external_system__tenant=tenant)
# Filter by endpoint
endpoint = self.request.GET.get('endpoint')
if endpoint:
queryset = queryset.filter(endpoint_id=endpoint)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by date range
start_date = self.request.GET.get('start_date')
end_date = self.request.GET.get('end_date')
if start_date:
queryset = queryset.filter(started_at__date__gte=start_date)
if end_date:
queryset = queryset.filter(completed_at__date__lte=end_date)
return queryset.select_related('endpoint').order_by('-completed_at')
def get_context_data(self, **kwargs):
tenant = self.request.user.tenant
context = super().get_context_data(**kwargs)
context['endpoints'] = IntegrationEndpoint.objects.filter(
external_system__tenant=tenant
).order_by('name')
context['selected_endpoint'] = self.request.GET.get('endpoint', '')
context['selected_status'] = self.request.GET.get('status', '')
context['start_date'] = self.request.GET.get('start_date', '')
context['end_date'] = self.request.GET.get('end_date', '')
return context
class IntegrationExecutionDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific integration execution.
"""
model = IntegrationExecution
template_name = 'integration/executions/integration_execution_detail.html'
context_object_name = 'execution'
def get_queryset(self):
return IntegrationExecution.objects.filter(tenant=self.request.user.tenant)
class WebhookEndpointListView(LoginRequiredMixin, ListView):
"""
List all webhook endpoints with filtering capabilities.
"""
model = WebhookEndpoint
template_name = 'integration/webhooks/webhook_endpoint_list.html'
context_object_name = 'webhook_endpoints'
paginate_by = 20
def get_queryset(self):
queryset = WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(endpoint_name__icontains=search) |
Q(description__icontains=search) |
Q(webhook_url__icontains=search)
)
# Filter by event type
event_type = self.request.GET.get('event_type')
if event_type:
queryset = queryset.filter(event_type=event_type)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
return queryset.order_by('endpoint_name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search'] = self.request.GET.get('search', '')
context['selected_event_type'] = self.request.GET.get('event_type', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
return context
class WebhookEndpointDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific webhook endpoint.
"""
model = WebhookEndpoint
template_name = 'integration/webhooks/webhook_endpoint_detail.html'
context_object_name = 'webhook_endpoint'
def get_queryset(self):
return WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
webhook_endpoint = self.get_object()
# Recent executions
context['recent_executions'] = WebhookExecution.objects.filter(
webhook_endpoint=webhook_endpoint
).order_by('-execution_time')[:10]
# Execution statistics
context['total_executions'] = WebhookExecution.objects.filter(
webhook_endpoint=webhook_endpoint
).count()
context['successful_executions'] = WebhookExecution.objects.filter(
webhook_endpoint=webhook_endpoint,
status='SUCCESS'
).count()
return context
class WebhookEndpointCreateView(LoginRequiredMixin, CreateView):
"""
Create a new webhook endpoint.
"""
model = WebhookEndpoint
form_class = WebhookEndpointForm
template_name = 'integration/webhooks/webhook_endpoint_form.html'
success_url = reverse_lazy('integration:webhook_endpoint_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'Webhook endpoint created successfully.')
return super().form_valid(form)
class WebhookEndpointUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing webhook endpoint.
"""
model = WebhookEndpoint
form_class = WebhookEndpointForm
template_name = 'integration/webhooks/webhook_endpoint_form.html'
def get_queryset(self):
return WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('integration:webhook_endpoint_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Webhook endpoint updated successfully.')
return super().form_valid(form)
class WebhookEndpointDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete a webhook endpoint.
"""
model = WebhookEndpoint
template_name = 'integration/webhooks/webhook_endpoint_confirm_delete.html'
success_url = reverse_lazy('integration:webhook_endpoint_list')
def get_queryset(self):
return WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
messages.success(request, 'Webhook endpoint deleted successfully.')
return super().delete(request, *args, **kwargs)
class WebhookExecutionListView(LoginRequiredMixin, ListView):
"""
List all webhook executions (read-only).
"""
model = WebhookExecution
template_name = 'integration/executions/webhook_execution_list.html'
context_object_name = 'webhook_executions'
paginate_by = 20
def get_queryset(self):
queryset = WebhookExecution.objects.filter(tenant=self.request.user.tenant)
# Filter by webhook endpoint
webhook_endpoint = self.request.GET.get('webhook_endpoint')
if webhook_endpoint:
queryset = queryset.filter(webhook_endpoint_id=webhook_endpoint)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by date range
start_date = self.request.GET.get('start_date')
end_date = self.request.GET.get('end_date')
if start_date:
queryset = queryset.filter(execution_time__date__gte=start_date)
if end_date:
queryset = queryset.filter(execution_time__date__lte=end_date)
return queryset.select_related('webhook_endpoint').order_by('-execution_time')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['webhook_endpoints'] = WebhookEndpoint.objects.filter(
tenant=self.request.user.tenant
).order_by('endpoint_name')
context['selected_webhook_endpoint'] = self.request.GET.get('webhook_endpoint', '')
context['selected_status'] = self.request.GET.get('status', '')
context['start_date'] = self.request.GET.get('start_date', '')
context['end_date'] = self.request.GET.get('end_date', '')
return context
class WebhookExecutionDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific webhook execution.
"""
model = WebhookExecution
template_name = 'integration/executions/webhook_execution_detail.html'
context_object_name = 'webhook_execution'
def get_queryset(self):
return WebhookExecution.objects.filter(tenant=self.request.user.tenant)
class IntegrationLogListView(LoginRequiredMixin, ListView):
"""
List all integration logs (read-only).
"""
model = IntegrationLog
template_name = 'integration/logs/integration_log_list.html'
context_object_name = 'integration_logs'
paginate_by = 50
def get_queryset(self):
queryset = IntegrationLog.objects.filter(tenant=self.request.user.tenant)
# Filter by log level
log_level = self.request.GET.get('log_level')
if log_level:
queryset = queryset.filter(log_level=log_level)
# Filter by component
component = self.request.GET.get('component')
if component:
queryset = queryset.filter(component__icontains=component)
# Filter by date range
start_date = self.request.GET.get('start_date')
end_date = self.request.GET.get('end_date')
if start_date:
queryset = queryset.filter(timestamp__date__gte=start_date)
if end_date:
queryset = queryset.filter(timestamp__date__lte=end_date)
return queryset.order_by('-timestamp')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['selected_log_level'] = self.request.GET.get('log_level', '')
context['selected_component'] = self.request.GET.get('component', '')
context['start_date'] = self.request.GET.get('start_date', '')
context['end_date'] = self.request.GET.get('end_date', '')
return context
class IntegrationLogDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific integration log.
"""
model = IntegrationLog
template_name = 'integration/logs/integration_log_detail.html'
context_object_name = 'integration_log'
def get_queryset(self):
return IntegrationLog.objects.filter(tenant=self.request.user.tenant)
@login_required
def integration_stats(request):
"""
Return integration statistics for dashboard updates.
"""
today = timezone.now().date()
context = {
'total_systems': ExternalSystem.objects.filter(tenant=request.user.tenant).count(),
'total_endpoints': IntegrationEndpoint.objects.filter(endpoint__external_system__tenant=request.user.tenant).count(),
'total_mappings': DataMapping.objects.filter(tenant=request.user.tenant).count(),
'total_webhooks': WebhookEndpoint.objects.filter(tenant=request.user.tenant).count(),
'executions_today': IntegrationExecution.objects.filter(
tenant=request.user.tenant,
execution_time__date=today
).count(),
'successful_executions': IntegrationExecution.objects.filter(
tenant=request.user.tenant,
execution_time__date=today,
status='SUCCESS'
).count(),
'healthy_systems': ExternalSystem.objects.filter(
tenant=request.user.tenant,
is_active=True,
last_health_check_status='HEALTHY'
).count(),
}
return render(request, 'integration/partials/integration_stats.html', context)
@login_required
def system_health(request):
"""
Return system health information for dashboard updates.
"""
context = {
'healthy_systems': ExternalSystem.objects.filter(
tenant=request.user.tenant,
is_active=True,
is_healthy=True
).count(),
'unhealthy_systems': ExternalSystem.objects.filter(
tenant=request.user.tenant,
is_active=True,
is_healthy=False
).count(),
}
return render(request, 'integration/partials/system_health.html', context)
@login_required
def test_connection(request, system_id):
"""
Test connection to an external system.
"""
try:
external_system = ExternalSystem.objects.get(
id=system_id,
tenant=request.user.tenant
)
# Simulate connection test (implement actual logic based on system type)
try:
# Basic URL connectivity test
response = requests.get(
external_system.base_url,
timeout=external_system.timeout_seconds or 30,
verify=False # In production, handle SSL verification properly
)
if response.status_code == 200:
external_system.last_health_check_time = timezone.now()
external_system.last_health_check_status = 'HEALTHY'
external_system.last_health_check_message = 'Connection successful'
external_system.save()
messages.success(request, f'Connection to {external_system.name} successful.')
else:
external_system.last_health_check_time = timezone.now()
external_system.last_health_check_status = 'UNHEALTHY'
external_system.last_health_check_message = f'HTTP {response.status_code}'
external_system.save()
messages.warning(request, f'Connection to {external_system.name} returned HTTP {response.status_code}.')
except requests.RequestException as e:
external_system.last_health_check_time = timezone.now()
external_system.last_health_check_status = 'UNHEALTHY'
external_system.last_health_check_message = str(e)
external_system.save()
messages.error(request, f'Connection to {external_system.name} failed: {str(e)}')
except ExternalSystem.DoesNotExist:
messages.error(request, 'External system not found.')
return redirect('integration:external_system_detail', pk=system_id)
@login_required
def execute_endpoint(request, endpoint_id):
"""
Execute an integration endpoint.
"""
try:
endpoint = IntegrationEndpoint.objects.get(
id=endpoint_id,
tenant=request.user.tenant
)
# Create execution record
execution = IntegrationExecution.objects.create(
tenant=request.user.tenant,
endpoint=endpoint,
execution_time=timezone.now(),
status='RUNNING',
triggered_by=request.user
)
try:
# Simulate endpoint execution (implement actual logic)
# This would involve calling the actual endpoint with proper data
execution.status = 'SUCCESS'
execution.completion_time = timezone.now()
execution.response_data = '{"status": "success", "message": "Endpoint executed successfully"}'
execution.save()
messages.success(request, f'Endpoint {endpoint.name} executed successfully.')
except Exception as e:
execution.status = 'FAILED'
execution.completion_time = timezone.now()
execution.error_message = str(e)
execution.save()
messages.error(request, f'Endpoint execution failed: {str(e)}')
except IntegrationEndpoint.DoesNotExist:
messages.error(request, 'Integration endpoint not found.')
return redirect('integration:integration_endpoint_detail', pk=endpoint_id)
@login_required
def test_data_mapping(request, mapping_id):
"""
Test a data mapping.
"""
try:
data_mapping = DataMapping.objects.get(
id=mapping_id,
tenant=request.user.tenant
)
# Simulate mapping test (implement actual logic)
# This would involve testing the transformation logic
messages.success(request, f'Data mapping {data_mapping.name} tested successfully.')
except DataMapping.DoesNotExist:
messages.error(request, 'Data mapping not found.')
return redirect('integration:data_mapping_detail', pk=mapping_id)
@login_required
def bulk_execute_endpoints(request):
"""
Execute multiple endpoints in bulk.
"""
endpoint_ids = request.POST.getlist('endpoint_ids')
if not endpoint_ids:
messages.error(request, 'No endpoints selected for execution.')
return redirect('integration:integration_endpoint_list')
executed_count = 0
failed_count = 0
for endpoint_id in endpoint_ids:
try:
endpoint = IntegrationEndpoint.objects.get(
id=endpoint_id,
tenant=request.user.tenant,
is_active=True
)
# Create execution record
execution = IntegrationExecution.objects.create(
tenant=request.user.tenant,
endpoint=endpoint,
execution_time=timezone.now(),
status='SUCCESS', # Simulate success
completion_time=timezone.now(),
triggered_by=request.user,
response_data='{"status": "success", "bulk_execution": true}'
)
executed_count += 1
except IntegrationEndpoint.DoesNotExist:
failed_count += 1
continue
except Exception:
failed_count += 1
continue
if executed_count > 0:
messages.success(request, f'Successfully executed {executed_count} endpoints.')
if failed_count > 0:
messages.warning(request, f'{failed_count} endpoints failed to execute.')
return redirect('integration:integration_endpoint_list')
#
#
# """
# Views for the integration app.
# """
# import json
# import logging
# import uuid
# from datetime import datetime, timedelta
#
# from django.shortcuts import render, get_object_or_404, redirect
# from django.http import JsonResponse, HttpResponse
# from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
# from django.views.generic.edit import FormView
# from django.views.decorators.csrf import csrf_exempt
# from django.views.decorators.http import require_POST
# from django.utils.decorators import method_decorator
# from django.contrib.auth.decorators import login_required, permission_required
# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# from django.urls import reverse, reverse_lazy
# from django.utils.translation import gettext_lazy as _
# from django.contrib import messages
# from django.db.models import Q, Count, Avg, Max, Min, Sum
# from django.db import transaction
# from django.utils import timezone
# from django.contrib.contenttypes.models import ContentType
#
# from .models import (
# ExternalSystem, IntegrationEndpoint, DataMapping,
# IntegrationExecution, WebhookEndpoint, WebhookExecution,
# IntegrationLog
# )
# from .forms import (
# ExternalSystemForm, IntegrationEndpointForm, DataMappingForm,
# WebhookEndpointForm, ManualIntegrationExecutionForm, IntegrationLogFilterForm
# )
#
# logger = logging.getLogger(__name__)
#
#
# class DashboardView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# Integration dashboard view showing an overview of integration status.
# """
# model = ExternalSystem
# template_name = 'integration/dashboard.html'
# context_object_name = 'external_systems'
# permission_required = 'integration.view_externalsystem'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return ExternalSystem.objects.filter(
# tenant=self.request.user.tenant
# ).prefetch_related('endpoints')
# return ExternalSystem.objects.none()
#
# def get_context_data(self, **kwargs):
# """Add additional context data for the dashboard."""
# context = super().get_context_data(**kwargs)
#
# # Add statistics for recent executions
# recent_executions = IntegrationExecution.objects.filter(
# endpoint__external_system__tenant=self.request.user.tenant,
# started_at__gte=timezone.now() - timedelta(days=7)
# )
#
# # Execution stats by status
# execution_stats = {
# 'total': recent_executions.count(),
# 'success': recent_executions.filter(status='SUCCESS').count(),
# 'error': recent_executions.filter(status='ERROR').count(),
# 'warning': recent_executions.filter(status='WARNING').count(),
# 'pending': recent_executions.filter(status__in=['PENDING', 'IN_PROGRESS']).count(),
# }
# context['execution_stats'] = execution_stats
#
# # Calculate success rate
# if execution_stats['total'] > 0:
# success_rate = (execution_stats['success'] / execution_stats['total']) * 100
# context['success_rate'] = round(success_rate, 1)
# else:
# context['success_rate'] = 0
#
# # Get recent logs
# context['recent_logs'] = IntegrationLog.objects.filter(
# tenant=self.request.user.tenant
# ).order_by('-timestamp')[:10]
#
# # Count active webhooks
# context['active_webhooks'] = WebhookEndpoint.objects.filter(
# tenant=self.request.user.tenant,
# is_active=True
# ).count()
#
# return context
#
#
# class ExternalSystemListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for external systems.
# """
# model = ExternalSystem
# template_name = 'integration/external_system/list.html'
# context_object_name = 'external_systems'
# permission_required = 'integration.view_externalsystem'
# paginate_by = 15
#
# def get_queryset(self):
# """Filter by user's tenant and apply search parameters."""
# queryset = ExternalSystem.objects.all()
#
# # Filter by tenant
# if hasattr(self.request.user, 'tenant'):
# queryset = queryset.filter(tenant=self.request.user.tenant)
#
# # Apply search filter if provided
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(system_type__icontains=search_query) |
# Q(description__icontains=search_query)
# )
#
# # Apply status filter if provided
# status_filter = self.request.GET.get('status')
# if status_filter == 'active':
# queryset = queryset.filter(is_active=True)
# elif status_filter == 'inactive':
# queryset = queryset.filter(is_active=False)
#
# # Apply system type filter if provided
# system_type = self.request.GET.get('system_type')
# if system_type:
# queryset = queryset.filter(system_type=system_type)
#
# return queryset.select_related('tenant')
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add filters to context
# context['search_query'] = self.request.GET.get('q', '')
# context['status_filter'] = self.request.GET.get('status', '')
# context['system_type'] = self.request.GET.get('system_type', '')
#
# # Add system type choices
# context['system_type_choices'] = ExternalSystem.SYSTEM_TYPE_CHOICES
#
# return context
#
#
# class ExternalSystemDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for an external system.
# """
# model = ExternalSystem
# template_name = 'integration/external_system/detail.html'
# context_object_name = 'external_system'
# permission_required = 'integration.view_externalsystem'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return ExternalSystem.objects.filter(tenant=self.request.user.tenant)
# return ExternalSystem.objects.none()
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add endpoints for this system
# context['endpoints'] = self.object.endpoints.all()
#
# # Add recent executions
# context['recent_executions'] = IntegrationExecution.objects.filter(
# endpoint__external_system=self.object
# ).order_by('-started_at')[:10]
#
# # Add health check timestamp
# if self.object.last_connected_at:
# last_check = timezone.now() - self.object.last_connected_at
# context['last_check_minutes'] = int(last_check.total_seconds() // 60)
#
# return context
#
#
# class ExternalSystemCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for an external system.
# """
# model = ExternalSystem
# form_class = ExternalSystemForm
# template_name = 'integration/external_system/form.html'
# permission_required = 'integration.add_externalsystem'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Add External System')
# context['submit_text'] = _('Create System')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('External system created successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:external_system_detail', kwargs={'pk': self.object.pk})
#
#
# class ExternalSystemUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for an external system.
# """
# model = ExternalSystem
# form_class = ExternalSystemForm
# template_name = 'integration/external_system/form.html'
# permission_required = 'integration.change_externalsystem'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return ExternalSystem.objects.filter(tenant=self.request.user.tenant)
# return ExternalSystem.objects.none()
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Edit External System')
# context['submit_text'] = _('Update System')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('External system updated successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:external_system_detail', kwargs={'pk': self.object.pk})
#
#
# class ExternalSystemDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for an external system.
# """
# model = ExternalSystem
# template_name = 'integration/external_system/confirm_delete.html'
# permission_required = 'integration.delete_externalsystem'
# success_url = reverse_lazy('integration:external_system_list')
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return ExternalSystem.objects.filter(tenant=self.request.user.tenant)
# return ExternalSystem.objects.none()
#
# def delete(self, request, *args, **kwargs):
# """Handle the delete action."""
# messages.success(request, _('External system deleted successfully.'))
# return super().delete(request, *args, **kwargs)
#
#
# class IntegrationEndpointListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for integration endpoints.
# """
# model = IntegrationEndpoint
# template_name = 'integration/endpoint/list.html'
# context_object_name = 'endpoints'
# permission_required = 'integration.view_integrationendpoint'
# paginate_by = 15
#
# def get_queryset(self):
# """Filter by user's tenant and apply search parameters."""
# queryset = IntegrationEndpoint.objects.all()
#
# # Filter by tenant
# if hasattr(self.request.user, 'tenant'):
# queryset = queryset.filter(external_system__tenant=self.request.user.tenant)
#
# # Filter by external system if provided
# system_id = self.request.GET.get('system')
# if system_id:
# queryset = queryset.filter(external_system_id=system_id)
#
# # Apply search filter if provided
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(description__icontains=search_query) |
# Q(endpoint_path__icontains=search_query)
# )
#
# # Apply direction filter if provided
# direction = self.request.GET.get('direction')
# if direction:
# queryset = queryset.filter(direction=direction)
#
# return queryset.select_related('external_system', 'external_system__tenant')
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add filters to context
# context['search_query'] = self.request.GET.get('q', '')
# context['direction'] = self.request.GET.get('direction', '')
# context['system_id'] = self.request.GET.get('system', '')
#
# # Add external systems for filter dropdown
# if hasattr(self.request.user, 'tenant'):
# context['external_systems'] = ExternalSystem.objects.filter(
# tenant=self.request.user.tenant
# )
#
# # Add direction choices
# context['direction_choices'] = IntegrationEndpoint.DIRECTION_CHOICES
#
# return context
#
#
# class IntegrationEndpointDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for an integration endpoint.
# """
# model = IntegrationEndpoint
# template_name = 'integration/endpoint/detail.html'
# context_object_name = 'endpoint'
# permission_required = 'integration.view_integrationendpoint'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return IntegrationEndpoint.objects.filter(
# external_system__tenant=self.request.user.tenant
# )
# return IntegrationEndpoint.objects.none()
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add data mappings
# context['data_mappings'] = self.object.data_mappings.all().order_by('priority')
#
# # Add recent executions
# context['recent_executions'] = self.object.executions.order_by('-started_at')[:10]
#
# # Add manual execution form
# context['execution_form'] = ManualIntegrationExecutionForm(
# user=self.request.user,
# initial={'endpoint': self.object.pk}
# )
#
# return context
#
#
# class IntegrationEndpointCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for an integration endpoint.
# """
# model = IntegrationEndpoint
# form_class = IntegrationEndpointForm
# template_name = 'integration/endpoint/form.html'
# permission_required = 'integration.add_integrationendpoint'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_initial(self):
# """Set initial values for the form."""
# initial = super().get_initial()
#
# # Set external system if provided in URL
# system_id = self.request.GET.get('system')
# if system_id:
# initial['external_system'] = system_id
#
# return initial
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Add Integration Endpoint')
# context['submit_text'] = _('Create Endpoint')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('Integration endpoint created successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:endpoint_detail', kwargs={'pk': self.object.pk})
#
#
# class IntegrationEndpointUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for an integration endpoint.
# """
# model = IntegrationEndpoint
# form_class = IntegrationEndpointForm
# template_name = 'integration/endpoint/form.html'
# permission_required = 'integration.change_integrationendpoint'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return IntegrationEndpoint.objects.filter(
# external_system__tenant=self.request.user.tenant
# )
# return IntegrationEndpoint.objects.none()
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Edit Integration Endpoint')
# context['submit_text'] = _('Update Endpoint')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('Integration endpoint updated successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:endpoint_detail', kwargs={'pk': self.object.pk})
#
#
# class IntegrationEndpointDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for an integration endpoint.
# """
# model = IntegrationEndpoint
# template_name = 'integration/endpoint/confirm_delete.html'
# permission_required = 'integration.delete_integrationendpoint'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return IntegrationEndpoint.objects.filter(
# external_system__tenant=self.request.user.tenant
# )
# return IntegrationEndpoint.objects.none()
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:endpoint_list')
#
# def delete(self, request, *args, **kwargs):
# """Handle the delete action."""
# messages.success(request, _('Integration endpoint deleted successfully.'))
# return super().delete(request, *args, **kwargs)
#
#
# class DataMappingListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for data mappings.
# """
# model = DataMapping
# template_name = 'integration/mapping/list.html'
# context_object_name = 'mappings'
# permission_required = 'integration.view_datamapping'
# paginate_by = 20
#
# def get_queryset(self):
# """Filter by user's tenant and apply search parameters."""
# queryset = DataMapping.objects.all()
#
# # Filter by tenant
# if hasattr(self.request.user, 'tenant'):
# queryset = queryset.filter(
# endpoint__external_system__tenant=self.request.user.tenant
# )
#
# # Filter by endpoint if provided
# endpoint_id = self.request.GET.get('endpoint')
# if endpoint_id:
# queryset = queryset.filter(endpoint_id=endpoint_id)
#
# # Apply search filter if provided
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(description__icontains=search_query) |
# Q(source_field__icontains=search_query) |
# Q(target_field__icontains=search_query)
# )
#
# # Apply mapping type filter if provided
# mapping_type = self.request.GET.get('mapping_type')
# if mapping_type:
# queryset = queryset.filter(mapping_type=mapping_type)
#
# return queryset.select_related(
# 'endpoint', 'endpoint__external_system', 'created_by'
# ).order_by('endpoint__name', 'priority')
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add filters to context
# context['search_query'] = self.request.GET.get('q', '')
# context['mapping_type'] = self.request.GET.get('mapping_type', '')
# context['endpoint_id'] = self.request.GET.get('endpoint', '')
#
# # Add endpoints for filter dropdown
# if hasattr(self.request.user, 'tenant'):
# context['endpoints'] = IntegrationEndpoint.objects.filter(
# external_system__tenant=self.request.user.tenant
# ).select_related('external_system')
#
# # Add mapping type choices
# context['mapping_type_choices'] = DataMapping.MAPPING_TYPE_CHOICES
#
# return context
#
#
# class DataMappingDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for a data mapping.
# """
# model = DataMapping
# template_name = 'integration/mapping/detail.html'
# context_object_name = 'mapping'
# permission_required = 'integration.view_datamapping'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return DataMapping.objects.filter(
# endpoint__external_system__tenant=self.request.user.tenant
# )
# return DataMapping.objects.none()
#
#
# class DataMappingCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for a data mapping.
# """
# model = DataMapping
# form_class = DataMappingForm
# template_name = 'integration/mapping/form.html'
# permission_required = 'integration.add_datamapping'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_initial(self):
# """Set initial values for the form."""
# initial = super().get_initial()
#
# # Set endpoint if provided in URL
# endpoint_id = self.request.GET.get('endpoint')
# if endpoint_id:
# initial['endpoint'] = endpoint_id
#
# return initial
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Add Data Mapping')
# context['submit_text'] = _('Create Mapping')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('Data mapping created successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# if 'endpoint' in self.request.GET:
# return reverse('integration:endpoint_detail',
# kwargs={'pk': self.request.GET.get('endpoint')})
# return reverse('integration:mapping_detail', kwargs={'pk': self.object.pk})
#
#
# class DataMappingUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for a data mapping.
# """
# model = DataMapping
# form_class = DataMappingForm
# template_name = 'integration/mapping/form.html'
# permission_required = 'integration.change_datamapping'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return DataMapping.objects.filter(
# endpoint__external_system__tenant=self.request.user.tenant
# )
# return DataMapping.objects.none()
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Edit Data Mapping')
# context['submit_text'] = _('Update Mapping')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('Data mapping updated successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:mapping_detail', kwargs={'pk': self.object.pk})
#
#
# class DataMappingDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for a data mapping.
# """
# model = DataMapping
# template_name = 'integration/mapping/confirm_delete.html'
# permission_required = 'integration.delete_datamapping'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return DataMapping.objects.filter(
# endpoint__external_system__tenant=self.request.user.tenant
# )
# return DataMapping.objects.none()
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# if self.object.endpoint:
# return reverse('integration:endpoint_detail',
# kwargs={'pk': self.object.endpoint.pk})
# return reverse('integration:mapping_list')
#
# def delete(self, request, *args, **kwargs):
# """Handle the delete action."""
# messages.success(request, _('Data mapping deleted successfully.'))
# return super().delete(request, *args, **kwargs)
#
#
# class WebhookEndpointListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for webhook endpoints.
# """
# model = WebhookEndpoint
# template_name = 'integration/webhook/list.html'
# context_object_name = 'webhooks'
# permission_required = 'integration.view_webhookendpoint'
# paginate_by = 15
#
# def get_queryset(self):
# """Filter by user's tenant and apply search parameters."""
# queryset = WebhookEndpoint.objects.all()
#
# # Filter by tenant
# if hasattr(self.request.user, 'tenant'):
# queryset = queryset.filter(tenant=self.request.user.tenant)
#
# # Apply search filter if provided
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(description__icontains=search_query) |
# Q(path__icontains=search_query)
# )
#
# # Apply security level filter if provided
# security_level = self.request.GET.get('security_level')
# if security_level:
# queryset = queryset.filter(security_level=security_level)
#
# # Apply status filter
# status_filter = self.request.GET.get('status')
# if status_filter == 'active':
# queryset = queryset.filter(is_active=True)
# elif status_filter == 'inactive':
# queryset = queryset.filter(is_active=False)
#
# return queryset.select_related('tenant')
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add filters to context
# context['search_query'] = self.request.GET.get('q', '')
# context['security_level'] = self.request.GET.get('security_level', '')
# context['status_filter'] = self.request.GET.get('status', '')
#
# # Add security level choices
# context['security_level_choices'] = WebhookEndpoint.SECURITY_LEVEL_CHOICES
#
# return context
#
#
# class WebhookEndpointDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for a webhook endpoint.
# """
# model = WebhookEndpoint
# template_name = 'integration/webhook/detail.html'
# context_object_name = 'webhook'
# permission_required = 'integration.view_webhookendpoint'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
# return WebhookEndpoint.objects.none()
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add recent executions
# context['recent_executions'] = WebhookExecution.objects.filter(
# webhook=self.object
# ).order_by('-timestamp')[:10]
#
# # Add webhook URL
# context['webhook_url'] = self.object.get_full_url()
#
# return context
#
#
# class WebhookEndpointCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for a webhook endpoint.
# """
# model = WebhookEndpoint
# form_class = WebhookEndpointForm
# template_name = 'integration/webhook/form.html'
# permission_required = 'integration.add_webhookendpoint'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Add Webhook Endpoint')
# context['submit_text'] = _('Create Webhook')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('Webhook endpoint created successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:webhook_detail', kwargs={'pk': self.object.pk})
#
#
# class WebhookEndpointUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for a webhook endpoint.
# """
# model = WebhookEndpoint
# form_class = WebhookEndpointForm
# template_name = 'integration/webhook/form.html'
# permission_required = 'integration.change_webhookendpoint'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
# return WebhookEndpoint.objects.none()
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# """Add context for the template."""
# context = super().get_context_data(**kwargs)
# context['title'] = _('Edit Webhook Endpoint')
# context['submit_text'] = _('Update Webhook')
# return context
#
# def form_valid(self, form):
# """Handle valid form."""
# messages.success(self.request, _('Webhook endpoint updated successfully.'))
# return super().form_valid(form)
#
# def get_success_url(self):
# """Return URL to redirect to on success."""
# return reverse('integration:webhook_detail', kwargs={'pk': self.object.pk})
#
#
# class WebhookEndpointDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for a webhook endpoint.
# """
# model = WebhookEndpoint
# template_name = 'integration/webhook/confirm_delete.html'
# permission_required = 'integration.delete_webhookendpoint'
# success_url = reverse_lazy('integration:webhook_list')
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return WebhookEndpoint.objects.filter(tenant=self.request.user.tenant)
# return WebhookEndpoint.objects.none()
#
# def delete(self, request, *args, **kwargs):
# """Handle the delete action."""
# messages.success(request, _('Webhook endpoint deleted successfully.'))
# return super().delete(request, *args, **kwargs)
#
#
# class IntegrationLogListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for integration logs.
# """
# model = IntegrationLog
# template_name = 'integration/log/list.html'
# context_object_name = 'logs'
# permission_required = 'integration.view_integrationlog'
# paginate_by = 50
#
# def get_queryset(self):
# """Filter by user's tenant and apply search parameters."""
# queryset = IntegrationLog.objects.all()
#
# # Filter by tenant
# if hasattr(self.request.user, 'tenant'):
# queryset = queryset.filter(tenant=self.request.user.tenant)
#
# # Get filter form
# form = IntegrationLogFilterForm(self.request.GET)
# if form.is_valid():
# # Apply integration name filter
# if form.cleaned_data.get('integration_name'):
# queryset = queryset.filter(
# integration_name__icontains=form.cleaned_data['integration_name']
# )
#
# # Apply event type filter
# if form.cleaned_data.get('event_type'):
# queryset = queryset.filter(
# event_type__icontains=form.cleaned_data['event_type']
# )
#
# # Apply status filter
# if form.cleaned_data.get('status'):
# queryset = queryset.filter(status=form.cleaned_data['status'])
#
# # Apply direction filter
# if form.cleaned_data.get('direction'):
# queryset = queryset.filter(direction=form.cleaned_data['direction'])
#
# # Apply date range filter
# if form.cleaned_data.get('date_from'):
# queryset = queryset.filter(
# timestamp__gte=form.cleaned_data['date_from']
# )
# if form.cleaned_data.get('date_to'):
# queryset = queryset.filter(
# timestamp__lte=form.cleaned_data['date_to']
# )
#
# # Apply related object filters
# if form.cleaned_data.get('related_object_type'):
# queryset = queryset.filter(
# related_object_type=form.cleaned_data['related_object_type']
# )
# if form.cleaned_data.get('related_object_id'):
# queryset = queryset.filter(
# related_object_id=form.cleaned_data['related_object_id']
# )
#
# return queryset.select_related('tenant', 'user', 'related_object_type').order_by('-timestamp')
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add filter form
# context['filter_form'] = IntegrationLogFilterForm(self.request.GET)
#
# return context
#
#
# class IntegrationLogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for an integration log.
# """
# model = IntegrationLog
# template_name = 'integration/log/detail.html'
# context_object_name = 'log'
# permission_required = 'integration.view_integrationlog'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return IntegrationLog.objects.filter(tenant=self.request.user.tenant)
# return IntegrationLog.objects.none()
#
#
# class IntegrationExecutionListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for integration executions.
# """
# model = IntegrationExecution
# template_name = 'integration/execution/list.html'
# context_object_name = 'executions'
# permission_required = 'integration.view_integrationexecution'
# paginate_by = 30
#
# def get_queryset(self):
# """Filter by user's tenant and apply search parameters."""
# queryset = IntegrationExecution.objects.all()
#
# # Filter by tenant
# if hasattr(self.request.user, 'tenant'):
# queryset = queryset.filter(endpoint__external_system__tenant=self.request.user.tenant)
#
# # Apply endpoint filter if provided
# endpoint_id = self.request.GET.get('endpoint')
# if endpoint_id:
# queryset = queryset.filter(endpoint_id=endpoint_id)
#
# # Apply status filter if provided
# status = self.request.GET.get('status')
# if status:
# queryset = queryset.filter(status=status)
#
# # Apply date range filter
# date_from = self.request.GET.get('date_from')
# if date_from:
# try:
# date_from = datetime.strptime(date_from, '%Y-%m-%d')
# queryset = queryset.filter(started_at__gte=date_from)
# except (ValueError, TypeError):
# pass
#
# date_to = self.request.GET.get('date_to')
# if date_to:
# try:
# date_to = datetime.strptime(date_to, '%Y-%m-%d')
# date_to = date_to.replace(hour=23, minute=59, second=59)
# queryset = queryset.filter(started_at__lte=date_to)
# except (ValueError, TypeError):
# pass
#
# return queryset.select_related(
# 'endpoint', 'endpoint__external_system', 'triggered_by'
# ).order_by('-started_at')
#
# def get_context_data(self, **kwargs):
# """Add additional context data."""
# context = super().get_context_data(**kwargs)
#
# # Add filters to context
# context['endpoint_id'] = self.request.GET.get('endpoint', '')
# context['status'] = self.request.GET.get('status', '')
# context['date_from'] = self.request.GET.get('date_from', '')
# context['date_to'] = self.request.GET.get('date_to', '')
#
# # Add status choices
# context['status_choices'] = IntegrationExecution.STATUS_CHOICES
#
# # Add endpoints for filter dropdown
# if hasattr(self.request.user, 'tenant'):
# context['endpoints'] = IntegrationEndpoint.objects.filter(
# external_system__tenant=self.request.user.tenant
# ).select_related('external_system')
#
# return context
#
#
# class IntegrationExecutionDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for an integration execution.
# """
# model = IntegrationExecution
# template_name = 'integration/execution/detail.html'
# context_object_name = 'execution'
# permission_required = 'integration.view_integrationexecution'
#
# def get_queryset(self):
# """Filter by user's tenant."""
# if hasattr(self.request.user, 'tenant'):
# return IntegrationExecution.objects.filter(
# endpoint__external_system__tenant=self.request.user.tenant
# )
# return IntegrationExecution.objects.none()
# class ManualExecutionView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
# """
# View for manually executing an integration endpoint.
# """
# form_class = ManualIntegrationExecutionForm
# template_name = 'integration/executions/manual_execution.html'
# permission_required = 'integration.add_integrationexecution'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_initial(self):
# """Set initial values for the form."""
# initial = super().get_initial()
#
# # Set endpoint if provided in URL
# endpoint_id = self.request.GET.get('endpoint')
# if endpoint_id:
# initial['endpoint'] = endpoint_id
#
# return initial
#
# def form_valid(self, form):
# """Execute the integration when the form is valid."""
# try:
# execution = form.execute()
# messages.success(
# self.request,
# _('Integration executed successfully. Status: {}').format(
# execution.get_status_display()
# )
# )
# return redirect('integration:execution_detail', pk=execution.pk)
# except Exception as e:
# messages.error(
# self.request,
# _('Error executing integration: {}').format(str(e))
# )
# return self.form_invalid(form)
@login_required
@permission_required('integration.change_integrationexecution')
def retry_execution(request, pk):
"""
View for retrying a failed integration execution.
"""
execution = get_object_or_404(IntegrationExecution, pk=pk)
# Check tenant access
if hasattr(request.user, 'tenant') and execution.endpoint.external_system.tenant != request.user.tenant:
messages.error(request, _('You do not have permission to retry this execution.'))
return redirect('integration:execution_list')
# Check if execution can be retried
if execution.status not in ['ERROR', 'WARNING']:
messages.error(request, _('Only failed executions can be retried.'))
return redirect('integration:execution_detail', pk=execution.pk)
# Retry the execution
new_execution = execution.retry(user=request.user)
if new_execution:
messages.success(request, _('Integration execution retried.'))
return redirect('integration:execution_detail', pk=new_execution.pk)
else:
messages.error(request, _('Failed to retry execution.'))
return redirect('integration:execution_detail', pk=execution.pk)
@login_required
@permission_required('integration.view_externalsystem')
def check_system_health(request, pk):
"""
View for checking the health of an external system.
"""
tenant = request.user.tenant
system = get_object_or_404(ExternalSystem, pk=pk)
# Check tenant access
if not tenant:
messages.error(request, _('You do not have permission to check this system.'))
return redirect('integration:external_system_list')
# Check the health
if system.check_health():
messages.success(request, _('Connection to {} is healthy.').format(system.name))
else:
messages.error(
request,
_('Connection to {} failed: {}').format(system.name, system.health_status_message)
)
return redirect('integration:external_system_detail', pk=system.pk)
@method_decorator(csrf_exempt, name='dispatch')
@require_POST
def webhook_receiver(request, path):
"""
View for receiving webhook calls from external systems.
This is a public endpoint that doesn't require authentication directly,
but validates the request using the webhook's security configuration.
"""
# Find the webhook by path
webhook = get_object_or_404(WebhookEndpoint, path=path, is_active=True)
# Create execution record
execution = WebhookExecution(
webhook=webhook,
client_ip=request.META.get('REMOTE_ADDR', '')
)
# Store headers
execution.headers = {key: value for key, value in request.headers.items()}
# Parse payload based on content type
try:
if request.content_type == 'application/json':
execution.payload = json.loads(request.body)
elif request.content_type == 'application/x-www-form-urlencoded':
execution.payload = dict(request.POST)
else:
execution.payload = {'raw': request.body.decode('utf-8', errors='replace')}
except Exception as e:
execution.status = 'REJECTED'
execution.error_message = f"Failed to parse payload: {str(e)}"
execution.response_code = 400
execution.save()
return JsonResponse(
{'error': 'Invalid payload format'},
status=400
)
# Validate security
if webhook.security_level != 'NONE':
security_valid = False
error_message = ''
if webhook.security_level == 'TOKEN':
# Check for token in Authorization header or query parameter
auth_header = request.headers.get('Authorization', '')
query_token = request.GET.get('token', '')
if auth_header.startswith('Bearer ') and auth_header[7:] == webhook.secret_token:
security_valid = True
elif query_token and query_token == webhook.secret_token:
security_valid = True
else:
error_message = 'Invalid or missing authentication token'
elif webhook.security_level == 'HMAC':
# Implement HMAC signature validation
signature = request.headers.get('X-Signature', '')
if not signature:
error_message = 'Missing signature header'
else:
# HMAC validation would go here
security_valid = True # Placeholder
elif webhook.security_level == 'IP':
# Check if client IP is in allowed list
client_ip = request.META.get('REMOTE_ADDR', '')
allowed_ips = [ip.strip() for ip in webhook.allowed_ips.split(',') if ip.strip()]
if not allowed_ips or client_ip in allowed_ips:
security_valid = True
else:
error_message = f'IP address {client_ip} not in allowed list'
if not security_valid:
execution.status = 'REJECTED'
execution.error_message = f"Security validation failed: {error_message}"
execution.response_code = 403
execution.save()
return JsonResponse(
{'error': 'Authentication failed'},
status=403
)
# Process the webhook
try:
# Import and call the handler function
module_path, function_name = webhook.handler_function.rsplit('.', 1)
module = __import__(module_path, fromlist=[function_name])
handler = getattr(module, function_name)
# Call the handler with the execution record
start_time = timezone.now()
result = handler(execution.payload, webhook=webhook, execution=execution)
processing_time = (timezone.now() - start_time).total_seconds() * 1000
# Update execution record
execution.status = 'SUCCESS'
execution.response_data = result
execution.response_code = 200
execution.processing_time_ms = int(processing_time)
execution.save()
# Return the result
return JsonResponse(result, status=200)
except Exception as e:
logger.exception(f"Error processing webhook {webhook.name}: {str(e)}")
# Update execution record
execution.status = 'ERROR'
execution.error_message = str(e)
execution.response_code = 500
execution.response_data = {'error': 'Internal server error'}
execution.save()
# Return error response
return JsonResponse(
{'error': 'Internal server error'},
status=500
)
@login_required
@permission_required('integration.change_webhookendpoint')
def regenerate_webhook_token(request, pk):
"""
View for regenerating a webhook's secret token.
"""
tenant = request.user.tenant
webhook = get_object_or_404(WebhookEndpoint, pk=pk)
# Check tenant access
if not tenant:
messages.error(request, _('You do not have permission to modify this webhook.'))
return redirect('integration:webhook_list')
# Regenerate the token
webhook.regenerate_token()
messages.success(request, _('Webhook token regenerated successfully.'))
return redirect('integration:webhook_detail', pk=webhook.pk)
@login_required
@permission_required('integration.view_integrationlog')
def integration_stats(request):
"""
View for displaying integration statistics.
"""
if hasattr(request.user, 'tenant'):
tenant = request.user.tenant
# Date range for stats
days = int(request.GET.get('days', 30))
end_date = timezone.now()
start_date = end_date - timedelta(days=days)
# Get logs for period
logs = IntegrationLog.objects.filter(
tenant=tenant,
timestamp__gte=start_date,
timestamp__lte=end_date
)
# Calculate statistics
stats = {
'total_count': logs.count(),
'success_count': logs.filter(status='SUCCESS').count(),
'error_count': logs.filter(status='ERROR').count(),
'warning_count': logs.filter(status='WARNING').count(),
'inbound_count': logs.filter(direction='INBOUND').count(),
'outbound_count': logs.filter(direction='OUTBOUND').count(),
}
# Calculate success rate
if stats['total_count'] > 0:
stats['success_rate'] = (stats['success_count'] / stats['total_count']) * 100
else:
stats['success_rate'] = 0
# Get top integration names
top_integrations = logs.values('integration_name') \
.annotate(count=Count('integration_name')) \
.order_by('-count')[:10]
# Get top error types
top_errors = logs.filter(status='ERROR') \
.values('error_message') \
.annotate(count=Count('error_message')) \
.order_by('-count')[:10]
# Get average response times
avg_duration = logs.aggregate(avg_duration=Avg('duration_ms'))
stats['avg_duration_ms'] = avg_duration['avg_duration'] or 0
context = {
'stats': stats,
'top_integrations': top_integrations,
'top_errors': top_errors,
'start_date': start_date,
'end_date': end_date,
'days': days,
}
return render(request, 'integration/partials/integration_stats.html', context)
messages.error(request, _('You do not have permission to view integration statistics.'))
return redirect('integration:dashboard')