chore: refactor lighthouse config singleton code

This commit is contained in:
Chandrapal Badshah
2025-10-09 13:13:57 +05:30
parent d70e8f0633
commit 218f8511f5
3 changed files with 17 additions and 102 deletions
-76
View File
@@ -3187,82 +3187,6 @@ class LighthouseTenantConfigSerializer(RLSSerializer):
}
class LighthouseTenantConfigCreateSerializer(RLSSerializer, BaseWriteSerializer):
"""
Create serializer for LighthouseTenantConfiguration.
Note: One record per tenant constraint is enforced by database and model.clean().
"""
class Meta:
model = LighthouseTenantConfiguration
fields = [
"business_context",
"default_provider",
"default_models",
]
def validate(self, attrs):
request = self.context.get("request")
tenant_id = self.context.get("tenant_id") or (
getattr(request, "tenant_id", None) if request else None
)
default_provider = attrs.get("default_provider", "")
default_models = attrs.get("default_models", {})
if default_provider:
supported = set(LighthouseProviderConfiguration.LLMProviderChoices.values)
if default_provider not in supported:
raise ValidationError(
{"default_provider": f"Unsupported provider '{default_provider}'."}
)
if not LighthouseProviderConfiguration.objects.filter(
tenant_id=tenant_id, provider_type=default_provider, is_active=True
).exists():
raise ValidationError(
{
"default_provider": f"No active configuration found for '{default_provider}'."
}
)
if default_models is not None and not isinstance(default_models, dict):
raise ValidationError(
{"default_models": "Must be an object mapping provider -> model_id."}
)
for provider_type, model_id in (default_models or {}).items():
provider_cfg = LighthouseProviderConfiguration.objects.filter(
tenant_id=tenant_id, provider_type=provider_type, is_active=True
).first()
if not provider_cfg:
raise ValidationError(
{
"default_models": f"No active configuration for provider '{provider_type}'."
}
)
if not LighthouseProviderModels.objects.filter(
tenant_id=tenant_id,
provider_configuration=provider_cfg,
model_id=model_id,
).exists():
raise ValidationError(
{
"default_models": f"Invalid model '{model_id}' for provider '{provider_type}'."
}
)
return super().validate(attrs)
def create(self, validated_data):
try:
return super().create(validated_data)
except IntegrityError:
raise ValidationError(
{"tenant_id": "Tenant Lighthouse configuration already exists."}
)
class LighthouseTenantConfigUpdateSerializer(BaseWriteSerializer):
class Meta:
model = LighthouseTenantConfiguration
+2 -2
View File
@@ -37,12 +37,12 @@ from api.v1.views import (
ScheduleViewSet,
SchemaView,
TaskViewSet,
TenantApiKeyViewSet,
TenantFinishACSView,
TenantMembersViewSet,
TenantViewSet,
UserRoleRelationshipView,
UserViewSet,
TenantApiKeyViewSet,
)
router = routers.DefaultRouter(trailing_slash=False)
@@ -154,7 +154,7 @@ urlpatterns = [
path(
"lighthouse/config",
LighthouseTenantConfigViewSet.as_view(
{"get": "retrieve", "post": "create", "patch": "partial_update"}
{"get": "list", "patch": "partial_update"}
),
name="lighthouse-config",
),
+15 -24
View File
@@ -171,7 +171,6 @@ from api.v1.serializers import (
LighthouseProviderConfigSerializer,
LighthouseProviderConfigUpdateSerializer,
LighthouseProviderModelsSerializer,
LighthouseTenantConfigCreateSerializer,
LighthouseTenantConfigSerializer,
LighthouseTenantConfigUpdateSerializer,
MembershipSerializer,
@@ -4354,35 +4353,29 @@ class LighthouseProviderConfigViewSet(BaseRLSViewSet):
@extend_schema_view(
list=extend_schema(
tags=["Lighthouse AI"],
summary="List tenant config",
description="List Lighthouse AI tenant-level settings for the current tenant.",
),
retrieve=extend_schema(
tags=["Lighthouse AI"],
summary="Get tenant config",
description="Retrieve tenant Lighthouse AI settings by ID.",
),
create=extend_schema(
tags=["Lighthouse AI"],
summary="Create tenant config",
description="Create Lighthouse AI tenant-level settings. Only one configuration is allowed per tenant.",
description="Retrieve current tenant-level Lighthouse AI settings. Returns a single configuration object.",
),
partial_update=extend_schema(
tags=["Lighthouse AI"],
summary="Update tenant config",
description="Update tenant-level settings. Validates that the default provider is configured and active and that default model IDs exist for the chosen providers.",
),
destroy=extend_schema(
tags=["Lighthouse AI"],
summary="Delete tenant config",
description="Delete tenant Lighthouse AI settings for the current tenant.",
description="Update tenant-level settings. Validates that the default provider is configured and active and that default model IDs exist for the chosen providers. Auto-creates configuration if it doesn't exist.",
),
)
class LighthouseTenantConfigViewSet(BaseRLSViewSet):
"""
Singleton endpoint for tenant-level Lighthouse AI configuration.
This viewset implements a true singleton pattern:
- GET returns the single configuration object (or 404 if not found)
- PATCH updates/creates the configuration (upsert semantics)
- No ID is required in the URL
"""
queryset = LighthouseTenantConfiguration.objects.all()
serializer_class = LighthouseTenantConfigSerializer
http_method_names = ["get", "post", "patch", "delete"]
http_method_names = ["get", "patch"]
def get_queryset(self):
if getattr(self, "swagger_fake_view", False):
@@ -4392,9 +4385,7 @@ class LighthouseTenantConfigViewSet(BaseRLSViewSet):
)
def get_serializer_class(self):
if self.action == "create":
return LighthouseTenantConfigCreateSerializer
elif self.action == "partial_update":
if self.action == "partial_update":
return LighthouseTenantConfigUpdateSerializer
return super().get_serializer_class()
@@ -4408,8 +4399,8 @@ class LighthouseTenantConfigViewSet(BaseRLSViewSet):
self.check_object_permissions(self.request, obj)
return obj
def retrieve(self, request, *args, **kwargs):
"""GET endpoint for singleton - no pk required."""
def list(self, request, *args, **kwargs):
"""GET endpoint for singleton - returns single object, not an array."""
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)