Marwan Alwali 25f548825b update
2025-08-27 18:45:14 +03:00

319 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# integration/management/commands/generate_integration_data.py
import random
import uuid
from datetime import datetime, timedelta
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.contrib.auth import get_user_model
from faker import Faker
from integration.models import (
ExternalSystem, IntegrationEndpoint,
DataMapping, IntegrationExecution,
WebhookEndpoint, WebhookExecution,
IntegrationLog
)
from core.models import Tenant
User = get_user_model()
fake = Faker('en_US')
class Command(BaseCommand):
help = "Generate sample data for the integration app"
# ------------------------------------------------------------------
# Utility helpers
# ------------------------------------------------------------------
@staticmethod
def random_choice(field, exclude=None):
"""Return a random value from a Django fields choices."""
choices = field.choices
if exclude:
choices = [c for c in choices if c[0] not in exclude]
return random.choice(choices)[0]
@staticmethod
def random_bool(chance=0.5):
return random.random() < chance
# ------------------------------------------------------------------
# Main entry point
# ------------------------------------------------------------------
def handle(self, *args, **options):
tenants = Tenant.objects.all()
if not tenants:
self.stdout.write(self.style.ERROR("No tenants found. Create tenants before generating data."))
return
for tenant in tenants:
self.generate_external_systems(tenant)
self.generate_webhooks(tenant)
self.stdout.write(self.style.SUCCESS("Integration data generation complete."))
# ------------------------------------------------------------------
# External system + endpoints
# ------------------------------------------------------------------
def generate_external_systems(self, tenant, count=5):
for _ in range(count):
system = ExternalSystem.objects.create(
tenant=tenant,
name=fake.company() + " " + self.random_choice(ExternalSystem.SYSTEM_TYPES,
exclude=['other']),
description=fake.text(max_nb_chars=200),
system_type=self.random_choice(ExternalSystem.SYSTEM_TYPES),
vendor=fake.company(),
version=f"{random.randint(1, 5)}.{random.randint(0, 9)}",
base_url=fake.url(),
host=fake.hostname(),
port=random.randint(1024, 65535),
authentication_type=self.random_choice(ExternalSystem.AUTHENTICATION_TYPES),
authentication_config=self._random_auth_config(),
configuration=self._random_config(),
timeout_seconds=random.randint(10, 60),
retry_attempts=random.randint(0, 5),
retry_delay_seconds=random.randint(1, 10),
is_active=self.random_bool(0.9),
is_healthy=self.random_bool(0.7),
health_check_interval=random.randint(120, 600),
connection_count=random.randint(0, 1000),
success_count=random.randint(0, 800),
failure_count=random.randint(0, 200),
last_used_at=timezone.now() - timedelta(days=random.randint(0, 30)),
created_by=User.objects.filter(is_staff=True).first()
)
self.generate_endpoints(system, count=3)
def generate_endpoints(self, system, count=3):
for _ in range(count):
endpoint = IntegrationEndpoint.objects.create(
external_system=system,
name=fake.word().title() + " API",
description=fake.text(max_nb_chars=150),
endpoint_type=self.random_choice(IntegrationEndpoint.ENDPOINT_TYPES),
path=f"/{fake.word()}/{fake.word()}",
method=self.random_choice(IntegrationEndpoint.METHODS),
direction=self.random_choice(IntegrationEndpoint.DIRECTIONS),
headers=self._random_headers(),
parameters=self._random_params(),
request_format="json",
response_format="json",
request_mapping=self._random_mapping(),
response_mapping=self._random_mapping(),
request_schema=self._random_schema(),
response_schema=self._random_schema(),
is_active=self.random_bool(0.9),
created_by=User.objects.filter(is_staff=True).first()
)
# Data mappings belong to an endpoint create a few of them
for _ in range(random.randint(0, 2)):
DataMapping.objects.create(
endpoint=endpoint,
name=fake.word().title() + " Mapping",
description=fake.text(max_nb_chars=100),
mapping_type=self.random_choice(DataMapping.MAPPING_TYPES),
source_field=fake.word(),
source_format="json",
source_validation=self._random_validation(),
target_field=fake.word(),
target_format="json",
target_validation=self._random_validation(),
transformation_type=self.random_choice(DataMapping.TRANSFORMATION_TYPES),
transformation_config=self._random_config(),
is_required=self.random_bool(),
validation_rules=self._random_validation(),
default_value=fake.word(),
is_active=self.random_bool(),
created_by=User.objects.filter(is_staff=True).first()
)
self.generate_executions(endpoint, count=random.randint(0, 5))
# ------------------------------------------------------------------
# Execution history
# ------------------------------------------------------------------
def generate_executions(self, endpoint, count=3):
for _ in range(count):
started = timezone.now() - timedelta(minutes=random.randint(0, 120))
completed = started + timedelta(seconds=random.randint(10, 120))
if self.random_bool(0.1):
completed = None # simulate inflight or stuck
exec = IntegrationExecution.objects.create(
endpoint=endpoint,
execution_type=self.random_choice(IntegrationExecution.EXECUTION_TYPES),
status=self.random_choice(IntegrationExecution.STATUSES),
started_at=started,
completed_at=completed,
request_data=self._random_json(),
response_data=self._random_json(),
request_size_bytes=random.randint(100, 2000),
response_size_bytes=random.randint(100, 2000),
processing_time_ms=random.randint(50, 2000),
network_time_ms=random.randint(10, 500),
error_message="" if self.random_bool(0.9) else fake.sentence(),
error_details=self._random_json() if self.random_bool(0.2) else {},
retry_count=random.randint(0, 3),
external_id=fake.uuid4(),
correlation_id=fake.uuid4(),
triggered_by=User.objects.filter(is_staff=True).first(),
metadata=self._random_json()
)
# Webhook executions (if the endpoint is a webhook)
if endpoint.endpoint_type == "webhook":
self.generate_webhook_executions(endpoint.external_system, exec)
# Logs one per execution
self.generate_logs(exec, count=random.randint(1, 4))
# ------------------------------------------------------------------
# Webhook endpoints & executions
# ------------------------------------------------------------------
def generate_webhooks(self, tenant, count=2):
for _ in range(count):
system = ExternalSystem.objects.filter(tenant=tenant).first()
if not system:
continue
webhook = WebhookEndpoint.objects.create(
external_system=system,
name=fake.word().title() + " Webhook",
description=fake.text(max_nb_chars=120),
url_path=f"/webhooks/{fake.slug()}",
allowed_methods=[self.random_choice(IntegrationEndpoint.METHODS)],
authentication_type=self.random_choice(WebhookEndpoint.AUTHENTICATION_TYPES),
authentication_config=self._random_auth_config(),
processing_config=self._random_config(),
rate_limit_per_minute=random.randint(30, 120),
rate_limit_per_hour=random.randint(500, 2000),
is_active=self.random_bool(0.9),
created_by=User.objects.filter(is_staff=True).first()
)
# Optionally link a data mapping
if DataMapping.objects.exists():
webhook.data_mapping = random.choice(list(DataMapping.objects.all()))
webhook.save()
self.generate_webhook_executions(webhook, None)
# Logs for the webhook itself
self.generate_logs(webhook, count=random.randint(1, 3))
def generate_webhook_executions(self, webhook, parent_exec=None):
for _ in range(random.randint(0, 3)):
method = self.random_choice(IntegrationEndpoint.METHODS)
status = self.random_choice(WebhookExecution.STATUSES)
received_at = timezone.now() - timedelta(seconds=random.randint(0, 300))
processed_at = received_at + timedelta(seconds=random.randint(0, 30)) if status in ("completed", "failed") else None
WebhookExecution.objects.create(
webhook=webhook,
method=method,
headers=self._random_headers(),
query_params=self._random_params(),
payload=self._random_json(),
payload_size_bytes=random.randint(100, 2000),
client_ip=fake.ipv4_public(),
user_agent=fake.user_agent(),
status=status,
received_at=received_at,
processed_at=processed_at,
processing_time_ms=random.randint(50, 2000) if processed_at else None,
response_status=200 if status == "completed" else random.choice([400, 401, 403, 500]),
response_data=self._random_json(),
error_message="" if status == "completed" else fake.sentence(),
error_details=self._random_json() if status != "completed" else {},
external_id=fake.uuid4(),
correlation_id=fake.uuid4(),
metadata=self._random_json()
)
# ------------------------------------------------------------------
# Integration logs (generic)
# ------------------------------------------------------------------
def generate_logs(self, source, count=5):
for _ in range(count):
timestamp = timezone.now() - timedelta(minutes=random.randint(0, 120))
log = IntegrationLog.objects.create(
external_system=getattr(source, "external_system", None),
endpoint=getattr(source, "endpoint", None),
execution=getattr(source, "execution", None),
level=self.random_choice(IntegrationLog.LOG_LEVELS),
category=self.random_choice(IntegrationLog.CATEGORIES),
message=fake.sentence(),
details=self._random_json(),
correlation_id=fake.uuid4(),
user=User.objects.filter(is_staff=True).first(),
timestamp=timestamp,
metadata=self._random_json()
)
# ------------------------------------------------------------------
# Random helpers
# ------------------------------------------------------------------
@staticmethod
def _random_json():
return {
"key1": fake.word(),
"key2": fake.word(),
"nested": {"sub": fake.word()}
}
@staticmethod
def _random_headers():
return {
"Authorization": f"Bearer {uuid.uuid4()}",
"Content-Type": "application/json"
}
@staticmethod
def _random_params():
return {
fake.word(): fake.word(),
fake.word(): fake.word()
}
@staticmethod
def _random_mapping():
return {
"source": fake.word(),
"target": fake.word()
}
@staticmethod
def _random_schema():
return {
"type": "object",
"properties": {
fake.word(): {"type": "string"},
fake.word(): {"type": "integer"}
}
}
@staticmethod
def _random_validation():
return {
"regex": "^[A-Za-z0-9_]+$",
"max_length": 50
}
@staticmethod
def _random_auth_config():
return {
"username": fake.user_name(),
"password": fake.password(),
"token_url": fake.url()
}
@staticmethod
def _random_config():
return {
"env": random.choice(["dev", "test", "prod"]),
"retries": random.randint(0, 5),
"timeout": random.randint(10, 60)
}