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
20 changes: 18 additions & 2 deletions frontend/src/lib/api/data-sets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,14 +361,22 @@ export class DataSetsApiClient extends BaseApiClient {
}

async addDataSetECommerceIntegration(dataSetId: number, pluginName: string, config: object): Promise<void> {
await fetch(
const response = await fetch(
`${this.apiBase}/api/data_sets/${dataSetId}/ecommerce_integration`,
{
...this._requestConfiguration(),
method: "POST",
body: JSON.stringify({ plugin_name: pluginName, config: config })
}
);

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new ApiError(`Failed to add e-commerce integration: ${response.statusText}`, {
data: errorData,
status: response.status
});
}
}

async configureDataSetECommerceIntegration(updated_source: CatalogSource): Promise<void> {
Expand All @@ -379,13 +387,21 @@ export class DataSetsApiClient extends BaseApiClient {
data_set_id: updated_source.data_set_id
};

await fetch(`${this.apiBase}/api/data_sets/${updated_source.data_set_id}/ecommerce_integration`,
const response = await fetch(`${this.apiBase}/api/data_sets/${updated_source.data_set_id}/ecommerce_integration`,
{
...this._requestConfiguration(),
body: JSON.stringify(body),
method: 'PATCH'
}
);

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new ApiError(`Failed to configure e-commerce integration: ${response.statusText}`, {
data: errorData,
status: response.status
});
}
}

async syncDataSetEcommerceIntegration(dataSetId: number): Promise<void> {
Expand Down
12 changes: 12 additions & 0 deletions server/catalog/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from utils.serializers import ParentDataContextSerializerMixin

from sync.document.registry import DocumentSourcePluginRegistry
from sync.ecommerce.registry import ECommerceIntegrationPluginRegistry
from sync.product.registry import ProductSourcePluginRegistry

from .models import DataSet, Document, DocumentSource, ECommerceIntegration, Product, ProductSource
Expand All @@ -21,6 +22,7 @@ class Meta:
"embedding_vector_dimensions",
]


class DataSetCreateSerializer(DataSetSerializer):
preconfigure_agents = serializers.BooleanField(write_only=True, required=False, default=False)

Expand Down Expand Up @@ -63,6 +65,15 @@ class DocumentSourceConfigSerializer(serializers.Serializer):
)


class ECommerceIntegrationConfigSerializer(serializers.Serializer):
configuration_args = PydanticModelField(
config_field_name="CONFIGURATION_ARGS",
plugin_registry_class=ECommerceIntegrationPluginRegistry,
allow_null=True,
default=None,
)


class ProductSourceSerializer(ParentDataContextSerializerMixin, serializers.ModelSerializer):
context_keys_to_propagate = ["plugin_name"]

Expand All @@ -88,6 +99,7 @@ class Meta:
class ECommerceIntegrationSerializer(ParentDataContextSerializerMixin, serializers.ModelSerializer):
context_keys_to_propagate = ["plugin_name"]

config = ECommerceIntegrationConfigSerializer()
task_id = serializers.CharField(read_only=True, required=False, allow_null=True)

class Meta:
Expand Down
12 changes: 7 additions & 5 deletions server/sync/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Generic, Self, Type, TypeVar
from typing import Generic, Type, TypeVar

from utils.base_registry import BaseRegistry


@dataclass
Expand All @@ -15,15 +17,15 @@ class DataSetSource:
T = TypeVar("T")


class SourcePluginRegistry(ABC):
class SourcePluginRegistry(Generic[T], BaseRegistry[T], ABC):
"""Registry of available source plugins registered in ECL system."""

def __init__(self):
self.plugins = self.load_plugins()

def load_plugins(self):
plugins = {}
for plugin_name, _ in self.get_plugins():
for plugin_name in self.get_plugin_names():
plugins[plugin_name] = self.get_plugin_class_by_name(plugin_name)
return plugins

Expand All @@ -42,11 +44,11 @@ def get_plugin_instance(self, data_set_source: DataSetSource):
return plugin_instance

@abstractmethod
def get_plugins(self) -> dict:
def get_plugin_names(self) -> list[str]:
pass

@abstractmethod
def get_plugin_class_by_name(self, path: str) -> Type[Self]:
def get_plugin_class_by_name(self, path: str) -> Type[T]:
pass


Expand Down
9 changes: 4 additions & 5 deletions server/sync/document/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

from django.conf import settings
from enthusiast_common import DocumentSourcePlugin
from utils.base_registry import BaseRegistry

from sync.base import SourcePluginRegistry


class DocumentSourcePluginRegistry(SourcePluginRegistry, BaseRegistry[DocumentSourcePlugin]):
class DocumentSourcePluginRegistry(SourcePluginRegistry[DocumentSourcePlugin]):
"""Registry of document source plugins."""

plugin_base = DocumentSourcePlugin

def get_plugins(self):
return settings.CATALOG_DOCUMENT_SOURCE_PLUGINS.items()
def get_plugin_names(self) -> list[str]:
return settings.CATALOG_DOCUMENT_SOURCE_PLUGINS.keys()

def get_plugin_class_by_name(self, name: str) -> Type[DocumentSourcePlugin]:
path = settings.CATALOG_DOCUMENT_SOURCE_PLUGINS[name]
return self._get_plugin_class_by_path(path)
return self._get_plugin_class_by_path(path)
20 changes: 9 additions & 11 deletions server/sync/ecommerce/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,15 @@

from django.conf import settings
from enthusiast_common.interfaces import ECommerceIntegrationPlugin
from utils.base_registry import BaseRegistry

from catalog.models import ECommerceIntegration
from sync.base import SourcePluginRegistry


class ECommerceIntegrationPluginRegistry(BaseRegistry[ECommerceIntegrationPlugin]):
class ECommerceIntegrationPluginRegistry(SourcePluginRegistry[ECommerceIntegrationPlugin]):
"""Registry of ecommerce integration plugins."""

plugin_base = ECommerceIntegrationPlugin

def get_plugin_instance(self, ecommerce_integration: ECommerceIntegration) -> ECommerceIntegrationPlugin:
plugin_classes_by_names = self._get_plugin_classes_by_names()
plugin_class = plugin_classes_by_names[ecommerce_integration.plugin_name]
plugin_instance = plugin_class(data_set_id=ecommerce_integration.data_set_id)
plugin_instance.set_runtime_arguments(ecommerce_integration.config)
return plugin_instance

def get_plugin_classes(self) -> List[Type[ECommerceIntegrationPlugin]]:
return [self._get_plugin_class_by_path(path) for path in self._get_plugin_paths()]

Expand All @@ -27,4 +19,10 @@ def _get_plugin_paths() -> List[str]:
return settings.CATALOG_ECOMMERCE_INTEGRATION_PLUGINS

def _get_plugin_classes_by_names(self) -> dict[str, Type[ECommerceIntegrationPlugin]]:
return { plugin_class.NAME: plugin_class for plugin_class in self.get_plugin_classes() }
return {plugin_class.NAME: plugin_class for plugin_class in self.get_plugin_classes()}

def get_plugin_class_by_name(self, name: str) -> Type[ECommerceIntegrationPlugin]:
return self._get_plugin_classes_by_names()[name]

def get_plugin_names(self) -> list[str]:
return list(self._get_plugin_classes_by_names().keys())
10 changes: 5 additions & 5 deletions server/sync/product/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

from django.conf import settings
from enthusiast_common import ProductSourcePlugin
from utils.base_registry import BaseRegistry

from sync.base import SourcePluginRegistry


class ProductSourcePluginRegistry(SourcePluginRegistry, BaseRegistry[ProductSourcePlugin]):
class ProductSourcePluginRegistry(SourcePluginRegistry[ProductSourcePlugin]):
"""Registry of product sync plugins."""

plugin_base = ProductSourcePlugin

def get_plugins(self):
return settings.CATALOG_PRODUCT_SOURCE_PLUGINS.items()
def get_plugin_names(self) -> list[str]:
return settings.CATALOG_PRODUCT_SOURCE_PLUGINS.keys()

def get_plugin_class_by_name(self, name: str) -> Type[ProductSourcePlugin]:
path = settings.CATALOG_PRODUCT_SOURCE_PLUGINS[name]
return self._get_plugin_class_by_path(path)
return self._get_plugin_class_by_path(path)
6 changes: 3 additions & 3 deletions server/sync/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ class PluginTypesMixin:
def get_choices(self, plugin_registry_class: Type[SourcePluginRegistry]):
plugin_registry = plugin_registry_class()
choices = []
for key, _ in plugin_registry.get_plugins():
for name in plugin_registry.get_plugin_names():
choices.append(
{
"name": key,
"name": name,
"configuration_args": get_model_descriptor_from_class_field(
plugin_registry.get_plugin_class_by_name(key), "CONFIGURATION_ARGS"
plugin_registry.get_plugin_class_by_name(name), "CONFIGURATION_ARGS"
),
}
)
Expand Down