From 08e993ed5d5eed95c81d01bf01ac3044eb46577f Mon Sep 17 00:00:00 2001
From: Maxim Podosochnyy <podosochnyy@perx.ru>
Date: Thu, 27 Mar 2025 15:08:05 +0300
Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?=
 =?UTF-8?q?=D0=BD=D1=8B=20=D1=84=D0=BB=D0=B0=D0=B3=D0=B8=20=D0=B4=D0=BB?=
 =?UTF-8?q?=D1=8F=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?=
 =?UTF-8?q?=D1=82=D0=B8=20=D1=83=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD=D0=B8=D1=8F?=
 =?UTF-8?q?=20=D0=B4=D0=BE=D0=BF=D1=83=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82?=
 =?UTF-8?q?=D0=B8=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?=
 =?UTF-8?q?=20/=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20item'?=
 =?UTF-8?q?=D0=BE=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../constants/collections.py                  |  2 +
 examples/extension_service/items.py           | 27 ++++++
 .../schemes/another_test_collection.json      | 33 +++++++
 examples/extension_service/servicer.py        | 27 +++++-
 perxis/extensions/item_models.py              | 35 ++++++--
 perxis/extensions/utils.py                    | 86 ++++++++++++++-----
 6 files changed, 179 insertions(+), 31 deletions(-)
 create mode 100644 examples/extension_service/items.py
 create mode 100644 examples/extension_service/schemes/another_test_collection.json

diff --git a/examples/extension_service/constants/collections.py b/examples/extension_service/constants/collections.py
index 9c9383e..1d36161 100644
--- a/examples/extension_service/constants/collections.py
+++ b/examples/extension_service/constants/collections.py
@@ -1,5 +1,7 @@
 TEST_COLLECTION_ID = "test_collection"
+ANOTHER_COLLECTION_ID = "another_test_collection"
 
 schemes_mapping = {
     TEST_COLLECTION_ID: "Тестовая коллекция",
+    ANOTHER_COLLECTION_ID: "Ещё одна тестовая коллекция",
 }
diff --git a/examples/extension_service/items.py b/examples/extension_service/items.py
new file mode 100644
index 0000000..370d2e5
--- /dev/null
+++ b/examples/extension_service/items.py
@@ -0,0 +1,27 @@
+from perxis.extensions.item_models import DataSourceData, SyncPolicyData
+
+
+DATASOURCE_DATA: DataSourceData = dict(
+    query="Some query",
+    content_type="json",
+)
+
+
+DATASOURCE_DATA_FOR_ANOTHER_COLLECTION: DataSourceData = dict(
+    query="Overrided some query",
+    with_update=False,
+    with_delete=False,
+)
+
+
+SYNC_POLICY_DATA: SyncPolicyData = dict(
+    key="id",
+    export_view=True,
+)
+
+SYNC_POLICY_DATA_ANOTHER_COLLECTION: SyncPolicyData = dict(
+    key="overrided",
+    export_view=False,
+    with_update=True,
+    with_delete=True,
+)
\ No newline at end of file
diff --git a/examples/extension_service/schemes/another_test_collection.json b/examples/extension_service/schemes/another_test_collection.json
new file mode 100644
index 0000000..3189935
--- /dev/null
+++ b/examples/extension_service/schemes/another_test_collection.json
@@ -0,0 +1,33 @@
+{
+    "ui": {
+        "options": {
+            "fields": [
+                "aaa",
+                "bbb"
+            ]
+        }
+    },
+    "type": "object",
+    "params": {
+        "inline": false,
+        "fields": {
+            "bbb": {
+                "title": "Ещё поле",
+                "ui": {
+                    "widget": "StringInput"
+                },
+                "type": "string",
+                "params": {}
+            },
+            "aaa": {
+                "title": "Какое то поле",
+                "ui": {
+                    "widget": "StringInput"
+                },
+                "type": "string",
+                "params": {}
+            }
+        }
+    },
+    "loaded": false
+}
diff --git a/examples/extension_service/servicer.py b/examples/extension_service/servicer.py
index 79aa7e5..1b317a0 100644
--- a/examples/extension_service/servicer.py
+++ b/examples/extension_service/servicer.py
@@ -2,6 +2,8 @@ import random
 
 from constants import extension
 from constants import collections as extension_collections
+from items import (SYNC_POLICY_DATA, SYNC_POLICY_DATA_ANOTHER_COLLECTION,
+                   DATASOURCE_DATA, DATASOURCE_DATA_FOR_ANOTHER_COLLECTION)
 
 
 from perxis.extensions.utils import datasource_items_from_collections, sync_policies_from_collections
@@ -78,9 +80,27 @@ class Servicer(ExtensionService):
         )
     ]
 
-    # items = (datasource_items_from_collections(extension_collections.schemes_mapping)
-    #         + sync_policies_from_collections(extension_collections.schemes_mapping))
-
+    items = (
+        datasource_items_from_collections(
+            collections_map=extension_collections.schemes_mapping,
+            datasource_data=DATASOURCE_DATA,
+            override_for_collections={
+                extension_collections.ANOTHER_COLLECTION_ID: DATASOURCE_DATA_FOR_ANOTHER_COLLECTION
+            },
+            with_update=True,
+            with_delete=True
+        )
+        + sync_policies_from_collections(
+            collections_map=extension_collections.schemes_mapping,
+            sync_policies_data=SYNC_POLICY_DATA,
+            override_for_collections={
+                extension_collections.ANOTHER_COLLECTION_ID: SYNC_POLICY_DATA_ANOTHER_COLLECTION,
+            },
+            with_delete=False,
+            with_update=False,
+        )
+    )
+    '''
     items = [
         DataSourceItem(
             collection_id="test_collection"
@@ -113,6 +133,7 @@ class Servicer(ExtensionService):
             ]
         )
     ]
+    '''
 
     async def action_get_current_organization_and_users(
             self,
diff --git a/perxis/extensions/item_models.py b/perxis/extensions/item_models.py
index 078ed22..02acd86 100644
--- a/perxis/extensions/item_models.py
+++ b/perxis/extensions/item_models.py
@@ -1,10 +1,32 @@
 import abc
+from typing import TypedDict, NotRequired
 
 from google.protobuf.struct_pb2 import Struct
 
 from perxis.extensions.item_rules import AbstractRule, IfCollectionExists, IfExtensionInstalled
 
 
+class DataSourceData(TypedDict):
+    query: NotRequired[str]
+    content_type: NotRequired[str]
+    exclude: NotRequired[bool]
+    with_update: NotRequired[bool]
+    with_delete: NotRequired[bool]
+
+
+class SyncPolicyData(TypedDict):
+    key: NotRequired[str]
+    export_view: NotRequired[bool]
+    remove_collection: NotRequired[bool]
+    deny_publish: NotRequired[bool]
+    deny_delete: NotRequired[bool]
+    deny_create: NotRequired[bool]
+    deny_read: NotRequired[bool]
+    hidden: NotRequired[bool]
+    with_update: NotRequired[bool]
+    with_delete: NotRequired[bool]
+
+
 class AbstractItem(metaclass=abc.ABCMeta):
     """
         Абстрактный класс для item'а. Нужен для определения общих свойств без реализации какого
@@ -109,7 +131,6 @@ class SyncPolicyItem(AbstractItem):
     """
         Класс для коллекции hoop_item_sync_policies расширения perxishoop
     """
-
     identifier_field = "collection"
 
     def __init__(
@@ -117,16 +138,16 @@ class SyncPolicyItem(AbstractItem):
         collection_id: str,
         name: str = "",
         key: str = "id",
-        export_view: bool = True,
+        export_view: bool = False,
         remove_collection: bool = False,
-        deny_publish: bool = True,
-        deny_delete: bool = True,
-        deny_create: bool = True,
+        deny_publish: bool = False,
+        deny_delete: bool = False,
+        deny_create: bool = False,
         deny_read: bool = False,
         hidden: bool = False,
         rules: list[AbstractRule] | None = None,
-        with_update: bool = True,
-        with_delete: bool = True,
+        with_update: bool = False,
+        with_delete: bool = False,
     ):
         self.collection_id = "hoop_item_sync_policies"
         self.rules = rules or [IfExtensionInstalled("perxishoop")]
diff --git a/perxis/extensions/utils.py b/perxis/extensions/utils.py
index d45242a..2fa717b 100644
--- a/perxis/extensions/utils.py
+++ b/perxis/extensions/utils.py
@@ -1,48 +1,92 @@
 from typing import Optional
 
 from perxis.extensions import manager_service_pb2
-from perxis.extensions.item_models import DataSourceItem, SyncPolicyItem
+from perxis.extensions.item_models import DataSourceItem, DataSourceData, SyncPolicyItem, SyncPolicyData
 
 
 def datasource_items_from_collections(
     collections_map: dict[str, str],
+    datasource_data: DataSourceData,
+    override_for_collections: dict[str, DataSourceData] | None = None,
     with_update: bool = True,
     with_delete: bool = True,
 ) -> list[DataSourceItem]:
     """
-        Создание записей источников данных на базе маппинга коллекций
+        Создание записей источников данных на базе маппинга коллекций.
+
+        Args:
+            collections_map: Dict РІРёРґР° [collection_id, collection_name]
+            datasource_data: Dict со структурой DataSourceData для item'ов коллекций
+            override_for_collections: Dict для переопределения значений для отдельных коллекций
+                РІРёРґР° [collection_id, DataSourceData]
+            with_update: Флаг для возможности обновления существующих записей расширением. Может быть переопределён
+                РІ override_for_collections
+            with_delete: Флаг для возможности удаления существующих записей расширением. Может быть переопределён
+                РІ override_for_collections
     """
 
-    return [
-        DataSourceItem(
-            collection_id=collection_id,
-            with_delete=with_delete,
-            with_update=with_update
-        )
-        for collection_id in collections_map
-        if collection_id
-    ]
+    if not isinstance(override_for_collections, dict):
+        override_for_collections = {}
+
+    items = []
+
+    for collection_id in collections_map:
+        if not collection_id:
+            continue
+
+        kwargs = {
+            "with_update": with_update,
+            "with_delete": with_delete,
+            **override_for_collections.get(collection_id, datasource_data),
+            "collection_id": collection_id,
+        }
+
+        items.append(DataSourceItem(**kwargs))
+
+    return items
 
 
 def sync_policies_from_collections(
     collections_map: dict[str, str],
+    sync_policies_data: SyncPolicyData,
+    override_for_collections: dict[str, SyncPolicyData] | None = None,
     with_update: bool = True,
     with_delete: bool = True,
 ) -> list[SyncPolicyItem]:
     """
         Создание записей синхронизации коллекций на базе маппинга коллекций
+
+        Args:
+            collections_map: Dict РІРёРґР° [collection_id, collection_name]
+            sync_policies_data: Dict со структурой SyncPolicyData для item'ов коллекций
+            override_for_collections: Dict для переопределения значений для отдельных коллекций
+                РІРёРґР° [collection_id, SyncPolicyData]
+            with_update: Флаг для возможности обновления существующих записей расширением. Может быть переопределён
+                РІ override_for_collections
+            with_delete: Флаг для возможности удаления существующих записей расширением. Может быть переопределён
+                РІ override_for_collections
     """
 
-    return [
-        SyncPolicyItem(
-            collection_id=collection_id,
-            name=collection_name,
-            with_update=with_update,
-            with_delete=with_delete,
-        )
-        for collection_id, collection_name in collections_map.items()
-        if collection_id
-    ]
+    if not isinstance(override_for_collections, dict):
+        override_for_collections = {}
+
+    items = []
+
+    for collection_id, collection_name in collections_map.items():
+        if not collection_id:
+            continue
+
+        kwargs = {
+            "with_update": with_update,
+            "with_delete": with_delete,
+            "name": collection_name,
+            **override_for_collections.get(collection_id, sync_policies_data),
+            "collection_id": collection_id,
+        }
+
+        items.append(SyncPolicyItem(**kwargs))
+
+    return items
 
 
 def get_extension_descriptor(
-- 
GitLab