From 0e95a58be6dcb0ae7d92d9929cedbf0c63a7fc8e Mon Sep 17 00:00:00 2001 From: Julien Barreau Date: Fri, 20 Dec 2024 10:17:23 +0100 Subject: [PATCH] fix(operator_capabilities): operator emulation wasn't expose to front end (#301) --- .github/actions/isort/action.yml | 2 +- .../django_demo/.forestadmin-schema.json | 4 +- .../forestadmin/agent_toolkit/agent.py | 2 + .../agent_toolkit/resources/capabilities.py | 11 ++-- .../resources/test_capabilities_resource.py | 51 +++++++++++++++++-- src/agent_toolkit/tests/test_agent_toolkit.py | 6 ++- 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/.github/actions/isort/action.yml b/.github/actions/isort/action.yml index 3067c0e1..e2a1b8f9 100644 --- a/.github/actions/isort/action.yml +++ b/.github/actions/isort/action.yml @@ -28,4 +28,4 @@ runs: with: sortPaths: ${{ inputs.current_package }} requirementsFiles: "requirements.txt ../../requirements.txt" - configurations: "--settings-file=../../.isort.cfg" \ No newline at end of file + configuration: "--settings-file=./.isort.cfg" \ No newline at end of file diff --git a/src/_example/django/django_demo/.forestadmin-schema.json b/src/_example/django/django_demo/.forestadmin-schema.json index 8add2794..b2850a5d 100644 --- a/src/_example/django/django_demo/.forestadmin-schema.json +++ b/src/_example/django/django_demo/.forestadmin-schema.json @@ -3542,10 +3542,10 @@ ], "meta": { "liana": "agent-python", - "liana_version": "1.18.5", + "liana_version": "1.17.0", "stack": { "engine": "python", - "engine_version": "3.11.11" + "engine_version": "3.12.4" } } } \ No newline at end of file diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/agent.py b/src/agent_toolkit/forestadmin/agent_toolkit/agent.py index d014a203..4c20df3f 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/agent.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/agent.py @@ -76,6 +76,8 @@ async def __mk_resources(self): self._resources: Resources = { "capabilities": CapabilitiesResource( self.customizer.composite_datasource, + await self.customizer.get_datasource(), + self._permission_service, self._ip_white_list_service, self.options, ), diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/resources/capabilities.py b/src/agent_toolkit/forestadmin/agent_toolkit/resources/capabilities.py index 997e8ba1..009efbdc 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/resources/capabilities.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/resources/capabilities.py @@ -2,9 +2,10 @@ from forestadmin.agent_toolkit.forest_logger import ForestLogger from forestadmin.agent_toolkit.options import Options +from forestadmin.agent_toolkit.resources.collections.base_collection_resource import BaseCollectionResource from forestadmin.agent_toolkit.resources.collections.decorators import authenticate, check_method, ip_white_list -from forestadmin.agent_toolkit.resources.ip_white_list_resource import IpWhitelistResource from forestadmin.agent_toolkit.services.permissions.ip_whitelist_service import IpWhiteListService +from forestadmin.agent_toolkit.services.permissions.permission_service import PermissionService from forestadmin.agent_toolkit.utils.context import HttpResponseBuilder, Request, RequestMethod, Response from forestadmin.agent_toolkit.utils.forest_schema.generator_field import SchemaFieldGenerator from forestadmin.datasource_toolkit.datasource_customizer.datasource_composite import CompositeDatasource @@ -17,14 +18,16 @@ DatasourceAlias = Union[Datasource[BoundCollection], DatasourceCustomizer] -class CapabilitiesResource(IpWhitelistResource): +class CapabilitiesResource(BaseCollectionResource): def __init__( self, composite_datasource: CompositeDatasource, + datasource: Union[Datasource, DatasourceCustomizer], + permission: PermissionService, ip_white_list_service: IpWhiteListService, options: Options, ): - super().__init__(ip_white_list_service, options) + super().__init__(datasource, permission, ip_white_list_service, options) self.composite_datasource: CompositeDatasource = composite_datasource @ip_white_list @@ -52,7 +55,7 @@ async def capabilities(self, request: Request) -> Response: return HttpResponseBuilder.build_success_response(ret) def _get_collection_capability(self, collection_name: str) -> Dict[str, Any]: - collection = self.composite_datasource.get_collection(collection_name) + collection = self.datasource.get_collection(collection_name) fields = [] for field_name, field_schema in collection.schema["fields"].items(): if is_column(field_schema): diff --git a/src/agent_toolkit/tests/resources/test_capabilities_resource.py b/src/agent_toolkit/tests/resources/test_capabilities_resource.py index 0ba6a52e..0e04db8d 100644 --- a/src/agent_toolkit/tests/resources/test_capabilities_resource.py +++ b/src/agent_toolkit/tests/resources/test_capabilities_resource.py @@ -17,6 +17,7 @@ from forestadmin.agent_toolkit.services.permissions.permission_service import PermissionService from forestadmin.agent_toolkit.utils.context import Request, RequestMethod, Response, User from forestadmin.datasource_toolkit.collections import Collection +from forestadmin.datasource_toolkit.datasource_customizer.datasource_customizer import DatasourceCustomizer from forestadmin.datasource_toolkit.datasources import Datasource from forestadmin.datasource_toolkit.interfaces.fields import FieldType, Operator, PrimitiveType @@ -94,6 +95,12 @@ def setUpClass(cls) -> None: "type": FieldType.COLUMN, "filter_operators": set([]), }, + "created_at": { + "column_type": PrimitiveType.DATE, + "is_primary_key": False, + "type": FieldType.COLUMN, + "filter_operators": set([Operator.EQUAL, Operator.GREATER_THAN, Operator.LESS_THAN]), + }, } # type:ignore ) cls.datasource.add_collection(cls.book_collection) @@ -108,9 +115,17 @@ def setUpClass(cls) -> None: timezone=zoneinfo.ZoneInfo("Europe/Paris"), request={"ip": "127.0.0.1"}, ) + cls.datasource_customizer = DatasourceCustomizer() + cls.datasource_customizer.add_datasource(cls.datasource) def setUp(self) -> None: - self.capabilities_resource = CapabilitiesResource(self.datasource, self.ip_white_list_service, self.options) + self.capabilities_resource = CapabilitiesResource( + self.datasource_customizer.composite_datasource, + self.loop.run_until_complete(self.datasource_customizer.get_datasource()), + self.permission_service, + self.ip_white_list_service, + self.options, + ) def test_dispatch_should_not_dispatch_to_capabilities_when_no_post_request(self): for method in [RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.PUT]: @@ -127,7 +142,7 @@ def test_dispatch_should_not_dispatch_to_capabilities_when_no_post_request(self) self.assertEqual(response.status, 405) - def test_dispatch_should_return_correct_collection_and_fields_capabilities(self): + def test_dispatch_should_return_correct_collection_and_fields_capabilities_with_emulated_operators(self): request = Request( method=RequestMethod.POST, query={}, @@ -148,10 +163,40 @@ def test_dispatch_should_return_correct_collection_and_fields_capabilities(self) { "name": "id", "type": "Number", - "operators": ["equal", "greater_than", "in", "less_than"], + "operators": ["blank", "equal", "greater_than", "in", "less_than", "missing"], }, {"name": "name", "type": "String", "operators": []}, {"name": "cost", "type": "Number", "operators": []}, + { + "name": "created_at", + "type": "Date", + "operators": [ + "after", + "after_x_hours_ago", + "before", + "before_x_hours_ago", + "blank", + "equal", + "future", + "greater_than", + "in", + "less_than", + "missing", + "past", + "previous_month", + "previous_month_to_date", + "previous_quarter", + "previous_quarter_to_date", + "previous_week", + "previous_week_to_date", + "previous_x_days", + "previous_x_days_to_date", + "previous_year", + "previous_year_to_date", + "today", + "yesterday", + ], + }, ], } ], diff --git a/src/agent_toolkit/tests/test_agent_toolkit.py b/src/agent_toolkit/tests/test_agent_toolkit.py index 2aceffeb..e3036b7b 100644 --- a/src/agent_toolkit/tests/test_agent_toolkit.py +++ b/src/agent_toolkit/tests/test_agent_toolkit.py @@ -100,7 +100,11 @@ def test_property_resources( mocked_authentication_resource.assert_called_once_with(agent._ip_white_list_service, agent.options) mocked_capabilities_resource.assert_called_once_with( - agent.customizer.composite_datasource, agent._ip_white_list_service, agent.options + agent.customizer.composite_datasource, + "fake_datasource", + agent._permission_service, + agent._ip_white_list_service, + agent.options, ) mocked_crud_resource.assert_called_once_with( agent.customizer.composite_datasource,