From 1a0fac0db8781ec85952ca7379cd39bdab8f06d8 Mon Sep 17 00:00:00 2001 From: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:24:58 +0530 Subject: [PATCH] feat: copy data to new lighthouse config tables during migration --- ...ighthouseproviderconfiguration_and_more.py | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/api/src/backend/api/migrations/0049_lighthouseproviderconfiguration_and_more.py b/api/src/backend/api/migrations/0049_lighthouseproviderconfiguration_and_more.py index 6f7f4b6500..7dea5a8fee 100644 --- a/api/src/backend/api/migrations/0049_lighthouseproviderconfiguration_and_more.py +++ b/api/src/backend/api/migrations/0049_lighthouseproviderconfiguration_and_more.py @@ -1,13 +1,90 @@ # Generated by Django 5.1.12 on 2025-10-09 07:50 +import json import uuid import django.db.models.deletion -from django.db import migrations, models +from cryptography.fernet import Fernet, InvalidToken +from django.conf import settings +from django.db import connections, migrations, models, transaction import api.rls +def migrate_lighthouse_configs_forward(apps, schema_editor): + """ + Migrate data from old LighthouseConfiguration to new multi-provider models. + Old system: one LighthouseConfiguration per tenant (always OpenAI). + """ + LighthouseConfiguration = apps.get_model("api", "LighthouseConfiguration") + LighthouseProviderConfiguration = apps.get_model( + "api", "LighthouseProviderConfiguration" + ) + LighthouseTenantConfiguration = apps.get_model( + "api", "LighthouseTenantConfiguration" + ) + LighthouseProviderModels = apps.get_model("api", "LighthouseProviderModels") + + fernet = Fernet(settings.SECRETS_ENCRYPTION_KEY.encode()) + + alias = schema_editor.connection.alias + conn = connections[alias] + + # Determine tenants that actually have old lighthouse configurations + with conn.cursor() as cur: + cur.execute("SELECT DISTINCT tenant_id FROM lighthouse_configurations") + tenant_ids = [row[0] for row in cur.fetchall()] + + for tenant_id in tenant_ids: + # Run per-tenant work in one atomic transaction and set RLS context + with transaction.atomic(using=alias): + with conn.cursor() as cur: + cur.execute("SET LOCAL api.tenant_id = %s", [str(tenant_id)]) + + old_config = ( + LighthouseConfiguration.objects.using(alias) + .filter(tenant_id=tenant_id) + .first() + ) + if not old_config: + continue + + try: + # Create OpenAI provider configuration for this tenant + api_key_decrypted = fernet.decrypt(bytes(old_config.api_key)).decode() + credentials_encrypted = fernet.encrypt( + json.dumps({"api_key": api_key_decrypted}).encode() + ) + provider_config = LighthouseProviderConfiguration.objects.using( + alias + ).create( + tenant_id=tenant_id, + provider_type="openai", + credentials=credentials_encrypted, + is_active=old_config.is_active, + ) + + # Create tenant configuration from old values + LighthouseTenantConfiguration.objects.using(alias).create( + tenant_id=tenant_id, + business_context=old_config.business_context or "", + default_provider="openai", + default_models={"openai": old_config.model}, + ) + + # Create initial provider model record + LighthouseProviderModels.objects.using(alias).create( + tenant_id=tenant_id, + provider_configuration=provider_config, + model_id=old_config.model, + default_parameters={}, + ) + + except (InvalidToken, Exception): + # Skip failed migrations for this tenant/config + continue + + class Migration(migrations.Migration): dependencies = [ ("api", "0048_api_key"), @@ -125,6 +202,11 @@ class Migration(migrations.Migration): on_delete=django.db.models.deletion.CASCADE, to="api.tenant" ), ), + # Migrate data from old LighthouseConfiguration to new multi-provider models + migrations.RunPython( + migrate_lighthouse_configs_forward, + reverse_code=migrations.RunPython.noop, + ), migrations.AddIndex( model_name="lighthouseproviderconfiguration", index=models.Index(