Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion services/budadmin/src/flows/AddAdapter/AdapterDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const AdapterDetail = () => {
})
}, [currentWorkflow])


const handleNext = async () => {
form.submit();
const result = await updateAdapterDetailWorkflow(adapterWorkflow?.adapterName, projectId);
Expand Down Expand Up @@ -64,7 +65,9 @@ export const AdapterDetail = () => {
name="adapterName"
label="Adapter deployment name"
placeholder="Enter adapter deployment name"
rules={[{ required: true, message: "Please enter deployment name" }]}
rules={[
{ required: true, message: "Please enter deployment name" }
]}
ClassNames="mt-[.4rem]"
infoText="Enter a name for the deployment of the adapter"
onChange={(e) => setAdapterWorkflow({ ...adapterWorkflow, "adapterName": e })}
Expand Down
64 changes: 45 additions & 19 deletions services/budapp/budapp/endpoint_ops/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

import aiohttp
from fastapi import status
from sqlalchemy import func, select
from sqlalchemy.sql import cast
from sqlalchemy.types import String as SqlAlchemyString

from budapp.commons import logging
from budapp.commons.db_utils import SessionMixin
Expand Down Expand Up @@ -1532,6 +1535,42 @@ async def add_worker_from_notification_event(self, payload: NotificationPayload)
)
await BudNotifyService().send_notification(notification_request)

async def _validate_adapter_name(self, adapter_name: str, endpoint_id: UUID, project_id: UUID) -> None:
"""Validate adapter name for duplicates within endpoint and project.

Args:
adapter_name: The name to validate
endpoint_id: The endpoint ID to check within
project_id: The project ID for endpoint name collision check

Raises:
ClientException: If validation fails
"""
if not adapter_name:
return

# Check for duplicate adapter names in the same endpoint (case-insensitive)
# Use scalars_all() to handle potential multiple results gracefully
stmt = select(AdapterModel).filter(
func.lower(cast(AdapterModel.name, SqlAlchemyString)) == func.lower(adapter_name),
AdapterModel.endpoint_id == endpoint_id,
AdapterModel.status != AdapterStatusEnum.DELETED
)
db_adapters = self.scalars_all(stmt)

if db_adapters:
raise ClientException("An adapter with this name already exists")

# Check if adapter name conflicts with endpoint names in the project
db_endpoint = await EndpointDataManager(self.session).retrieve_by_fields(
EndpointModel,
{"name": adapter_name, "project_id": project_id},
missing_ok=True,
exclude_fields={"status": EndpointStatusEnum.DELETED},
)
if db_endpoint:
raise ClientException("Name already taken in the project")

async def add_adapter_workflow(self, current_user_id: UUID, request: AddAdapterRequest) -> None:
"""Add adapter workflow."""
step_number = request.step_number
Expand Down Expand Up @@ -1609,25 +1648,6 @@ async def add_adapter_workflow(self, current_user_id: UUID, request: AddAdapterR
if db_adapters:
raise ClientException("Adapter is already added in the endpoint")

if adapter_name:
db_adapters = await AdapterDataManager(self.session).retrieve_by_fields(
AdapterModel,
{"name": adapter_name, "endpoint_id": endpoint_id},
missing_ok=True,
exclude_fields={"status": AdapterStatusEnum.DELETED},
)
if db_adapters:
raise ClientException("Adapter name is already taken in the endpoint")

db_endpoint = await EndpointDataManager(self.session).retrieve_by_fields(
EndpointModel,
{"name": adapter_name, "project_id": project_id},
missing_ok=True,
exclude_fields={"status": EndpointStatusEnum.DELETED},
)
if db_endpoint:
raise ClientException("Name already taken in the project")

# Prepare workflow step data
workflow_step_data = AddAdapterWorkflowStepData(
endpoint_id=endpoint_id,
Expand Down Expand Up @@ -1657,6 +1677,9 @@ async def add_adapter_workflow(self, current_user_id: UUID, request: AddAdapterR

if db_current_workflow_step:
logger.info(f"Workflow {db_workflow.id} step {current_step_number} already exists")

# Validate adapter name on every call (not just first time)
await self._validate_adapter_name(adapter_name, endpoint_id, project_id)

# Update workflow step data in db
db_workflow_step = await WorkflowStepDataManager(self.session).update_by_fields(
Expand All @@ -1666,6 +1689,9 @@ async def add_adapter_workflow(self, current_user_id: UUID, request: AddAdapterR
logger.info(f"Workflow {db_workflow.id} step {current_step_number} updated")
else:
logger.info(f"Creating workflow step {current_step_number} for workflow {db_workflow.id}")

# Validate adapter name for new workflow steps
await self._validate_adapter_name(adapter_name, endpoint_id, project_id)

# Insert step details in db
db_workflow_step = await WorkflowStepDataManager(self.session).insert_one(
Expand Down
Loading