From 0330356ea2ab578167b901970ecd65edf28e257c Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Sat, 15 Nov 2025 16:00:05 +0500 Subject: [PATCH 1/3] feat: settings, delete port validation --- api/api/db/logic/list_events.py | 94 ------------------- api/api/db/logic/node_link.py | 19 +++- api/api/db/logic/process_schema.py | 45 --------- api/api/db/logic/ps_node.py | 23 ++++- api/api/endpoints/process_schema.py | 35 +++---- api/api/endpoints/ps_node.py | 50 +++++----- api/api/schemas/process/process_schema.py | 22 +---- .../process/process_version_archive.py | 13 --- api/api/schemas/process/ps_node.py | 19 +--- api/api/services/endpoints/process_schema.py | 89 +++++++++++------- api/api/services/endpoints/ps_node.py | 35 +------ 11 files changed, 140 insertions(+), 304 deletions(-) delete mode 100644 api/api/schemas/process/process_version_archive.py diff --git a/api/api/db/logic/list_events.py b/api/api/db/logic/list_events.py index 85a7cef..b50cc00 100644 --- a/api/api/db/logic/list_events.py +++ b/api/api/db/logic/list_events.py @@ -121,100 +121,6 @@ async def get_list_events_page_DTO( ) -async def get_list_events_page_by_creator_id( - connection: AsyncConnection, creator_id: int, page: int, limit: int -) -> Optional[AllListEventResponse]: - """ - Получает список событий заданного создателя по значениям page и limit и creator_id. - """ - - first_event = page * limit - limit - query = ( - select( - list_events_table.c.id, - list_events_table.c.name, - list_events_table.c.title, - list_events_table.c.creator_id, - list_events_table.c.created_at, - list_events_table.c.schema, - list_events_table.c.state, - list_events_table.c.status, - ) - .where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id - .order_by(list_events_table.c.id) - .offset(first_event) - .limit(limit) - ) - - count_query = ( - select(func.count()) - .select_from(list_events_table) - .where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id - ) - - result = await connection.execute(query) - count_result = await connection.execute(count_query) - - events_data = result.mappings().all() - total_count = count_result.scalar() - total_pages = math.ceil(total_count / limit) - - # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные - validated_list_event = all_list_event_adapter.validate_python(events_data) - - return AllListEventResponse( - list_event=validated_list_event, - amount_count=total_count, - amount_pages=total_pages, - current_page=page, - limit=limit, - ) - - -async def get_list_events_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]: - """ - Получает список событий заданного создателя по значениям page и limit. - """ - - first_event = page * limit - (limit) - - query = ( - select( - list_events_table.c.id, - list_events_table.c.name, - list_events_table.c.title, - list_events_table.c.creator_id, - list_events_table.c.created_at, - list_events_table.c.schema, - list_events_table.c.state, - list_events_table.c.status, - ) - .order_by(list_events_table.c.id) - .offset(first_event) - .limit(limit) - ) - - count_query = select(func.count()).select_from(list_events_table) - - result = await connection.execute(query) - count_result = await connection.execute(count_query) - - events_data = result.mappings().all() - total_count = count_result.scalar() - total_pages = math.ceil(total_count / limit) - - # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные - validated_list_event = all_list_event_adapter.validate_python(events_data) - - return AllListEventResponse( - list_event=validated_list_event, - amount_count=total_count, - amount_pages=total_pages, - current_page=page, - limit=limit, - ) - - async def get_list_events_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: """ Получает list events по name. diff --git a/api/api/db/logic/node_link.py b/api/api/db/logic/node_link.py index 85a5f0a..ca8d9b3 100644 --- a/api/api/db/logic/node_link.py +++ b/api/api/db/logic/node_link.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List from datetime import datetime, timezone @@ -79,3 +79,20 @@ async def create_node_link_schema( await connection.commit() return await get_last_node_link_by_creator_and_ps_id(connection, creator_id, validated_link_schema.from_id) + + +async def get_all_node_links_by_next_node_ids(connection: AsyncConnection, next_node_ids: List[int]) -> List[NodeLink]: + """ + Получает все активные node_link для списка next_node_id одним запросом. + """ + if not next_node_ids: + return [] + + query = select(node_link_table).where( + node_link_table.c.next_node_id.in_(next_node_ids), node_link_table.c.status == NodeLinkStatus.ACTIVE.value + ) + + node_link_db_cursor = await connection.execute(query) + node_links_data = node_link_db_cursor.mappings().all() + + return [NodeLink.model_validate(link_data) for link_data in node_links_data] diff --git a/api/api/db/logic/process_schema.py b/api/api/db/logic/process_schema.py index c953eb8..ec097e1 100644 --- a/api/api/db/logic/process_schema.py +++ b/api/api/db/logic/process_schema.py @@ -141,51 +141,6 @@ async def update_process_schema_by_id(connection: AsyncConnection, update_values await connection.commit() -async def update_process_schema_settings_by_id( - connection: AsyncConnection, process_schema_id: int, node_data: Dict[str, Any] -): - """ - Добавляет новый узел в массив 'nodes' в настройках процесса. - Если массив 'nodes' не существует, создает его. - """ - # Получаем текущие settings - query = select(process_schema_table.c.settings).where(process_schema_table.c.id == process_schema_id) - result = await connection.execute(query) - current_settings = result.scalar_one_or_none() - - # Если settings пустые, создаем пустой словарь - if current_settings is None: - current_settings = {} - - # Инициализируем массив nodes, если его нет - if "nodes" not in current_settings: - current_settings["nodes"] = [] - - # Добавляем новый узел в массив - current_settings["nodes"].append(node_data) - - # Обновляем поле settings - await connection.execute( - process_schema_table.update() - .where(process_schema_table.c.id == process_schema_id) - .values(settings=current_settings) - ) - - await connection.commit() - - -async def get_last_created_process_schema(connection: AsyncConnection) -> Optional[int]: - """ - Получает ID последней созданной схемы процесса. - """ - query = select(process_schema_table.c.id).order_by(desc(process_schema_table.c.id)).limit(1) - - result = await connection.execute(query) - last_id = result.scalar_one_or_none() - - return last_id - - async def create_process_schema( connection: AsyncConnection, creator_id: int, title: str, description: str ) -> Optional[int]: diff --git a/api/api/db/logic/ps_node.py b/api/api/db/logic/ps_node.py index ad7389c..c77b860 100644 --- a/api/api/db/logic/ps_node.py +++ b/api/api/db/logic/ps_node.py @@ -1,4 +1,4 @@ -from typing import Optional, List +from typing import Optional, List, Dict, Any from datetime import datetime, timezone @@ -8,7 +8,6 @@ from sqlalchemy.ext.asyncio import AsyncConnection from orm.tables.process import ps_node_table, node_link_table, process_schema_table from api.schemas.process.ps_node import Ps_Node -from model_nodes.node_listen_models import ListenNodeCoreSchema from orm.tables.process import NodeStatus @@ -49,18 +48,34 @@ async def get_last_ps_node_by_creator_and_ps_id( return Ps_Node.model_validate(ps_node_data) +async def get_all_ps_nodes_by_ps_id(connection: AsyncConnection, ps_id: int) -> List[Ps_Node]: + """ + Получает все активные ps_node для данной process_schema. + """ + query = select(ps_node_table).where( + ps_node_table.c.ps_id == ps_id, ps_node_table.c.status == NodeStatus.ACTIVE.value + ) + + ps_node_db_cursor = await connection.execute(query) + ps_nodes_data = ps_node_db_cursor.mappings().all() + + return [Ps_Node.model_validate(node_data) for node_data in ps_nodes_data] + + async def create_ps_node_schema( connection: AsyncConnection, validated_schema, + node_descriptor, creator_id: int, -) -> Optional[ListenNodeCoreSchema]: + settings_payload: Optional[Dict[str, Any]] = None, +) -> Optional[Ps_Node]: """ Создает нове поле в таблице process_schema_table. """ query = insert(ps_node_table).values( ps_id=validated_schema.ps_id, node_type=validated_schema.node_type, - settings=validated_schema.data.model_dump(), + settings=settings_payload if settings_payload is not None else node_descriptor.model_dump(), creator_id=creator_id, created_at=datetime.now(timezone.utc), status=NodeStatus.ACTIVE.value, diff --git a/api/api/endpoints/process_schema.py b/api/api/endpoints/process_schema.py index 1902540..741b217 100644 --- a/api/api/endpoints/process_schema.py +++ b/api/api/endpoints/process_schema.py @@ -75,16 +75,16 @@ async def get_all_process_schema_endpoint( return to_camel_dict(process_schema_page.model_dump()) -@api_router.get("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +@api_router.get("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchemaResponse) async def get_process_schema_endpoint( process_schema_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): service = ProcessSchemaService(connection) - process_schema_validation = await service.get(process_schema_id) + process_schema_response = await service.get(process_schema_id) - if process_schema_validation is None: + if process_schema_response is None: raise create_operation_error( message="Process schema not found", status_code=status.HTTP_404_NOT_FOUND, @@ -92,16 +92,9 @@ async def get_process_schema_endpoint( ) validator = UserRoleValidator(connection) - await validator.validate_ownership(current_user, process_schema_validation.creator_id) + await validator.validate_ownership(current_user, process_schema_response.process_schema.creator_id) - if process_schema_id is None: - raise create_operation_error( - message="Process schema not found", - status_code=status.HTTP_404_NOT_FOUND, - details={"process_schema_id": process_schema_id}, - ) - - return to_camel_dict(process_schema_validation.model_dump()) + return to_camel_dict(process_schema_response.model_dump()) @api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchemaResponse) @@ -125,9 +118,9 @@ async def update_process_schema_endpoint( current_user=Depends(get_current_user), ): service = ProcessSchemaService(connection) - process_schema_validation = await service.get(process_schema_id) + process_schema_response = await service.get(process_schema_id) - if process_schema_validation is None: + if process_schema_response is None: raise create_operation_error( message="Process schema not found", status_code=status.HTTP_404_NOT_FOUND, @@ -135,14 +128,14 @@ async def update_process_schema_endpoint( ) validator = UserRoleValidator(connection) - await validator.validate_ownership(current_user, process_schema_validation.creator_id) + await validator.validate_ownership(current_user, process_schema_response.process_schema.creator_id) updated_values = process_schema_update.model_dump(by_alias=True, exclude_none=True) if not updated_values: - return process_schema_validation + return process_schema_response.process_schema - process_schema = await service.update(process_schema_id, updated_values, process_schema_validation) + process_schema = await service.update(process_schema_id, updated_values, process_schema_response.process_schema) return process_schema @@ -154,9 +147,9 @@ async def delete_process_schema_endpoint( current_user=Depends(get_current_user), ): service = ProcessSchemaService(connection) - process_schema_validation = await service.get(process_schema_id) + process_schema_response = await service.get(process_schema_id) - if process_schema_validation is None: + if process_schema_response is None: raise create_operation_error( message="Process schema not found", status_code=status.HTTP_404_NOT_FOUND, @@ -164,8 +157,8 @@ async def delete_process_schema_endpoint( ) validator = UserRoleValidator(connection) - await validator.validate_ownership(current_user, process_schema_validation.creator_id) + await validator.validate_ownership(current_user, process_schema_response.process_schema.creator_id) - await service.delete(process_schema_id, process_schema_validation) + await service.delete(process_schema_id, process_schema_response.process_schema) return HTTPException(status_code=status.HTTP_200_OK, detail="Process schema deleted successfully") diff --git a/api/api/endpoints/ps_node.py b/api/api/endpoints/ps_node.py index 815acfb..4f8fb2a 100644 --- a/api/api/endpoints/ps_node.py +++ b/api/api/endpoints/ps_node.py @@ -61,20 +61,20 @@ async def delete_ps_node_endpoint( details={"next_node_id": ps_node_delete_data.next_node_id}, ) - is_connected = await check_node_connection( - connection, ps_node_delete_data.node_id, ps_node_delete_data.next_node_id, int(ps_node_delete_data.port) - ) + # is_connected = await check_node_connection( + # connection, ps_node_delete_data.node_id, ps_node_delete_data.next_node_id, int(ps_node_delete_data.port) + # ) - if not is_connected: - raise create_validation_error( - message="Node connection validation failed", - status_code=status.HTTP_400_BAD_REQUEST, - details={ - "node_id": ps_node_delete_data.node_id, - "next_node_id": ps_node_delete_data.next_node_id, - "port": ps_node_delete_data.port, - }, - ) + # if not is_connected: + # raise create_validation_error( + # message="Node connection validation failed", + # status_code=status.HTTP_400_BAD_REQUEST, + # details={ + # "node_id": ps_node_delete_data.node_id, + # "next_node_id": ps_node_delete_data.next_node_id, + # "port": ps_node_delete_data.port, + # }, + # ) service = PsNodeService(connection) try: @@ -153,21 +153,21 @@ async def create_ps_node_endpoint( details={"parent_id": parent_id, "expected_ps_id": target_ps_id, "actual_ps_id": parent_node.ps_id}, ) - parent_port_number = node_instance_validated.parent_port_number + # parent_port_number = node_instance_validated.parent_port_number - parent_settings = parent_node.settings or {} - available_port_numbers = [] + # parent_settings = parent_node.settings or {} + # available_port_numbers = [] - for key, value in parent_settings.items(): - if "port" in key.lower() and isinstance(value, int): - available_port_numbers.append(value) + # for key, value in parent_settings.items(): + # if "port" in key.lower() and isinstance(value, int): + # available_port_numbers.append(value) - if parent_port_number not in available_port_numbers: - raise create_validation_error( - message="Parent port number is invalid", - status_code=status.HTTP_400_BAD_REQUEST, - details={"parent_id": parent_id, "parent_settings": parent_settings}, - ) + # if parent_port_number not in available_port_numbers: + # raise create_validation_error( + # message="Parent port number is invalid", + # status_code=status.HTTP_400_BAD_REQUEST, + # details={"parent_id": parent_id, "parent_settings": parent_settings}, + # ) service = PsNodeService(connection) try: diff --git a/api/api/schemas/process/process_schema.py b/api/api/schemas/process/process_schema.py index 9bc7721..65254fe 100644 --- a/api/api/schemas/process/process_schema.py +++ b/api/api/schemas/process/process_schema.py @@ -1,7 +1,7 @@ from datetime import datetime -from typing import Any, Dict, Optional, List +from typing import Any, Dict, List -from orm.tables.process import ProcessStatus, NodeType +from orm.tables.process import ProcessStatus from pydantic import Field from api.schemas.base import Base @@ -19,22 +19,6 @@ class ProcessSchema(Base): status: ProcessStatus -class ProcessSchemaSettingsNodeLink(Base): - id: int - link_name: str - parent_port_number: int - from_id: int - to_id: int - - -class ProcessSchemaSettingsNode(Base): - id: int - node_type: NodeType - from_node: Optional[Dict[str, Any]] = None - data: Dict[str, Any] # Переименовано с 'from' на 'from_node' - links: Optional[List[Dict[str, Any]]] = None - - class ProcessSchemaResponse(Base): process_schema: ProcessSchema - node_listen: Ps_NodeFrontResponse + nodes: List[Ps_NodeFrontResponse] diff --git a/api/api/schemas/process/process_version_archive.py b/api/api/schemas/process/process_version_archive.py deleted file mode 100644 index 38d369e..0000000 --- a/api/api/schemas/process/process_version_archive.py +++ /dev/null @@ -1,13 +0,0 @@ -from datetime import datetime -from typing import Any, Dict - -from api.schemas.base import Base - - -class ProcessStatusSchema(Base): - id: int - version: int - snapshot: Dict[str, Any] - owner_id: int - created_at: datetime - is_last: int diff --git a/api/api/schemas/process/ps_node.py b/api/api/schemas/process/ps_node.py index 49d7bb3..0722d9a 100644 --- a/api/api/schemas/process/ps_node.py +++ b/api/api/schemas/process/ps_node.py @@ -28,21 +28,6 @@ class Ps_Node(Base): status: NodeStatus -class Ps_NodeFrontResponseLink(Base): - id: int - link_name: str - parent_port_number: int - from_id: int - to_id: int - - -class Ps_NodeFrontResponseNode(Base): - id: int - node_type: NodeType - data: Dict[str, Any] # Переименовано с 'from' на 'from_node' - - class Ps_NodeFrontResponse(Base): - description: Optional[Dict[str, Any]] = None - node: Optional[Ps_NodeFrontResponseNode] = None - links: Optional[List[Dict[str, Any]]] = None + node: Optional[Dict[str, Any]] = None + link: Optional[List[Dict[str, Any]]] = None diff --git a/api/api/services/endpoints/process_schema.py b/api/api/services/endpoints/process_schema.py index 244693e..749ebaa 100644 --- a/api/api/services/endpoints/process_schema.py +++ b/api/api/services/endpoints/process_schema.py @@ -7,12 +7,12 @@ from api.db.logic.process_schema import ( get_process_schema_page_DTO, update_process_schema_by_id, create_process_schema, - update_process_schema_settings_by_id, ) -from api.db.logic.ps_node import create_ps_node_schema -from api.schemas.process.process_schema import ProcessSchema, ProcessSchemaSettingsNode +from api.db.logic.ps_node import create_ps_node_schema, get_all_ps_nodes_by_ps_id +from api.db.logic.node_link import get_all_node_links_by_next_node_ids +from api.schemas.process.process_schema import ProcessSchema, ProcessSchemaResponse from api.schemas.endpoints.process_schema import AllProcessSchemaResponse, ProcessSchemaFilterDTO, ProcessSchemaUpdate -from api.schemas.process.ps_node import Ps_NodeFrontResponse, Ps_NodeFrontResponseNode +from api.schemas.process.ps_node import Ps_NodeFrontResponse from orm.tables.process import NodeType from core import VorkNodeRegistry from model_nodes import ListenNodeData @@ -31,11 +31,40 @@ class ProcessSchemaService: """ return await get_process_schema_page_DTO(self.connection, filter_dto) - async def get(self, process_schema_id: int) -> Optional[ProcessSchema]: + async def get(self, process_schema_id: int) -> Optional[ProcessSchemaResponse]: """ - Получает схему процесса по ID. + Получает схему процесса по ID со всеми нодами и линками. """ - return await get_process_schema_by_id(self.connection, process_schema_id) + process_schema = await get_process_schema_by_id(self.connection, process_schema_id) + if process_schema is None: + return None + + nodes = await get_all_ps_nodes_by_ps_id(self.connection, process_schema_id) + + node_ids = [node.id for node in nodes] + all_links = await get_all_node_links_by_next_node_ids(self.connection, node_ids) + + links_by_node_id = {} + for link in all_links: + if link.next_node_id not in links_by_node_id: + links_by_node_id[link.next_node_id] = [] + links_by_node_id[link.next_node_id].append(link) + + nodes_response = [] + for node in nodes: + node_links = links_by_node_id.get(node.id, []) + links_list = [{"link": link.model_dump()} for link in node_links] + + ps_node_front_response = Ps_NodeFrontResponse( + node=node.model_dump(), + link=links_list, + ) + nodes_response.append(ps_node_front_response) + + return ProcessSchemaResponse( + process_schema=process_schema, + nodes=nodes_response, + ) async def create(self, creator_id: int) -> Dict[str, Any]: """ @@ -63,35 +92,27 @@ class ProcessSchemaService: validated_start_schema = start_node.validate() - db_start_schema = await create_ps_node_schema(self.connection, validated_start_schema, creator_id) - - node = ProcessSchemaSettingsNode( - id=db_start_schema.id, - node_type=NodeType.LISTEN.value, - data=validated_start_schema.data.model_dump(), - from_node=None, - links=None, - ) - - settings_dict = {"node": node.model_dump(mode="json")} - - await update_process_schema_settings_by_id(self.connection, process_schema_new.id, settings_dict) - - process_schema_new = await get_process_schema_by_id(self.connection, node_id) - - ps_node_front_response = Ps_NodeFrontResponse( - description=node_descriptor.model_dump(), - node=Ps_NodeFrontResponseNode( - id=db_start_schema.id, node_type=NodeType.LISTEN.value, data=validated_start_schema.data.model_dump() - ), - link=None, - ) - - response_data = { - "process_schema": process_schema_new.model_dump(), - "node_listen": ps_node_front_response.model_dump(), + start_settings_payload = { + **node_descriptor.model_dump(), + **validated_start_schema.data.model_dump(), } + db_start_schema = await create_ps_node_schema( + self.connection, + validated_start_schema, + node_descriptor, + creator_id, + start_settings_payload, + ) + + ps_node_front_response = Ps_NodeFrontResponse( + node=db_start_schema.model_dump(), + link=[], + ) + response_data = { + "process_schema": process_schema_new.model_dump(), + "nodes": [ps_node_front_response], # Список объектов, а не словарей + } return response_data async def update(self, process_schema_id: int, update_data: dict, process_schema: ProcessSchema) -> ProcessSchema: diff --git a/api/api/services/endpoints/ps_node.py b/api/api/services/endpoints/ps_node.py index 5711f9d..260afb7 100644 --- a/api/api/services/endpoints/ps_node.py +++ b/api/api/services/endpoints/ps_node.py @@ -7,12 +7,9 @@ from api.db.logic.ps_node import ( create_ps_node_schema, ) from api.db.logic.node_link import get_last_link_name_by_node_id, create_node_link_schema -from api.db.logic.process_schema import update_process_schema_settings_by_id -from api.schemas.process.process_schema import ProcessSchemaSettingsNodeLink, ProcessSchemaSettingsNode -from api.schemas.process.ps_node import Ps_NodeFrontResponse, Ps_NodeFrontResponseNode +from api.schemas.process.ps_node import Ps_NodeFrontResponse from core import VorkNodeRegistry, VorkNodeLink from model_nodes import VorkNodeLinkData -from api.utils.to_camel_dict import to_camel_dict class PsNodeService: @@ -45,7 +42,7 @@ class PsNodeService: node_instance = vork_node(data=ps_node_data, links=links) node_instance_validated = node_instance.validate() - db_ps_node = await create_ps_node_schema(self.connection, node_instance_validated, creator_id) + db_ps_node = await create_ps_node_schema(self.connection, node_instance_validated, node_descriptor, creator_id) link_name = await get_last_link_name_by_node_id(self.connection, db_ps_node.ps_id) link_data = VorkNodeLinkData( @@ -60,33 +57,9 @@ class PsNodeService: db_node_link = await create_node_link_schema(self.connection, validated_link, creator_id) - links_settings = ProcessSchemaSettingsNodeLink( - id=db_node_link.id, - link_name=db_node_link.link_name, - parent_port_number=db_node_link.link_point_id, - from_id=db_node_link.node_id, - to_id=db_node_link.next_node_id, - ) - - node_settings = ProcessSchemaSettingsNode( - id=db_ps_node.id, - node_type=db_ps_node.node_type, - data=node_instance_validated.data.model_dump(), - from_node=None, - links=[{"links": links_settings.model_dump()}], - ) - - settings_dict = {"node": node_settings.model_dump(mode="json")} - await update_process_schema_settings_by_id(self.connection, db_ps_node.ps_id, settings_dict) - ps_node_front_response = Ps_NodeFrontResponse( - description=node_descriptor.model_dump(), - node=Ps_NodeFrontResponseNode( - id=db_ps_node.id, - node_type=db_ps_node.node_type, - data=to_camel_dict(node_instance_validated.data.model_dump()), - ), - links=[{"links": links_settings.model_dump()}], + node=db_ps_node.model_dump(), + link=[{"link": db_node_link.model_dump()}], ) return ps_node_front_response -- 2.39.5 From a70973032f484f9bb83c9a3d52c74534a42d801b Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Tue, 18 Nov 2025 12:12:58 +0500 Subject: [PATCH 2/3] fix: deprecated typings --- api/api/db/logic/account.py | 13 +++--- api/api/db/logic/auth.py | 8 ++-- api/api/db/logic/keyring.py | 7 ++- api/api/db/logic/list_events.py | 11 ++--- api/api/db/logic/node_link.py | 10 ++--- api/api/db/logic/process_schema.py | 8 ++-- api/api/db/logic/ps_node.py | 18 ++++---- api/api/endpoints/account.py | 14 +++--- api/api/endpoints/list_events.py | 14 +++--- api/api/endpoints/process_schema.py | 14 +++--- api/api/error/error_handlers.py | 16 +++---- api/api/error/error_model/error_types.py | 6 +-- api/api/schemas/account/account.py | 9 ++-- api/api/schemas/account/account_keyring.py | 5 +-- api/api/schemas/endpoints/account.py | 45 ++++++++++---------- api/api/schemas/endpoints/account_keyring.py | 10 ++--- api/api/schemas/endpoints/list_events.py | 26 +++++------ api/api/schemas/endpoints/process_schema.py | 26 +++++------ api/api/schemas/events/list_events.py | 4 +- api/api/schemas/process/node_link.py | 4 +- api/api/schemas/process/process_schema.py | 6 +-- api/api/schemas/process/ps_node.py | 10 ++--- api/api/services/auth.py | 4 +- api/api/services/endpoints/account.py | 5 +-- api/api/services/endpoints/keyring.py | 3 +- api/api/services/endpoints/list_events.py | 9 ++-- api/api/services/endpoints/process_schema.py | 8 ++-- api/api/services/endpoints/profile.py | 3 +- api/api/services/endpoints/ps_node.py | 6 +-- api/api/utils/node_counter.py | 5 +-- 30 files changed, 147 insertions(+), 180 deletions(-) diff --git a/api/api/db/logic/account.py b/api/api/db/logic/account.py index 08eb51e..4c16184 100644 --- a/api/api/db/logic/account.py +++ b/api/api/db/logic/account.py @@ -1,7 +1,6 @@ import math from datetime import datetime, timezone from enum import Enum -from typing import Optional from sqlalchemy import insert, select, func, or_, and_, asc, desc from sqlalchemy.ext.asyncio import AsyncConnection @@ -11,9 +10,7 @@ from api.schemas.account.account import User from api.schemas.endpoints.account import all_user_adapter, AllUser, AllUserResponse, UserCreate, UserFilterDTO -async def get_user_account_page_DTO( - connection: AsyncConnection, filter_dto: UserFilterDTO -) -> Optional[AllUserResponse]: +async def get_user_account_page_DTO(connection: AsyncConnection, filter_dto: UserFilterDTO) -> AllUserResponse | None: """ Получает список пользователей с пагинацией, фильтрацией и сортировкой через DTO объект. Поддерживает: @@ -118,7 +115,7 @@ async def get_user_account_page_DTO( ) -async def get_user_by_id(connection: AsyncConnection, user_id: int) -> Optional[AllUser]: +async def get_user_by_id(connection: AsyncConnection, user_id: int) -> AllUser | None: """ Получает юзера по id. """ @@ -133,7 +130,7 @@ async def get_user_by_id(connection: AsyncConnection, user_id: int) -> Optional[ return User.model_validate(user) -async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional[User]: +async def get_user_by_login(connection: AsyncConnection, login: str) -> User | None: """ Получает юзера по login. """ @@ -147,7 +144,7 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional return User.model_validate(user_data) -async def update_user_by_id(connection: AsyncConnection, update_values, user) -> Optional[User]: +async def update_user_by_id(connection: AsyncConnection, update_values, user) -> User | None: """ Вносит изменеия в нужное поле таблицы account_table. """ @@ -156,7 +153,7 @@ async def update_user_by_id(connection: AsyncConnection, update_values, user) -> await connection.commit() -async def create_user(connection: AsyncConnection, user: UserCreate, creator_id: int) -> Optional[AllUser]: +async def create_user(connection: AsyncConnection, user: UserCreate, creator_id: int) -> AllUser | None: """ Создает нове поле в таблице account_table. """ diff --git a/api/api/db/logic/auth.py b/api/api/db/logic/auth.py index f3b940f..7859a89 100644 --- a/api/api/db/logic/auth.py +++ b/api/api/db/logic/auth.py @@ -1,5 +1,3 @@ -from typing import Optional - from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncConnection from enum import Enum @@ -15,7 +13,7 @@ from api.utils.key_id_gen import KeyIdGenerator from datetime import datetime, timezone -async def get_user(connection: AsyncConnection, login: str) -> tuple[Optional[AllUser], Optional[AccountKeyring]]: +async def get_user(connection: AsyncConnection, login: str) -> tuple[AllUser | None, AccountKeyring | None]: query = ( select(account_table, account_keyring_table) .join(account_keyring_table, account_table.c.id == account_keyring_table.c.owner_id) @@ -51,7 +49,7 @@ async def get_user(connection: AsyncConnection, login: str) -> tuple[Optional[Al return user, password -async def upgrade_old_refresh_token(connection: AsyncConnection, refresh_token) -> Optional[User]: +async def upgrade_old_refresh_token(connection: AsyncConnection, refresh_token) -> User | None: new_status = KeyStatus.EXPIRED update_query = ( @@ -71,7 +69,7 @@ async def upgrade_old_refresh_token(connection: AsyncConnection, refresh_token) async def add_new_refresh_token( connection: AsyncConnection, new_refresh_token, new_refresh_token_expires_time, user -) -> Optional[User]: +) -> User | None: new_refresh_token = account_keyring_table.insert().values( owner_id=user.id, key_type=KeyType.REFRESH_TOKEN, diff --git a/api/api/db/logic/keyring.py b/api/api/db/logic/keyring.py index e0c98b2..7fa3b8f 100644 --- a/api/api/db/logic/keyring.py +++ b/api/api/db/logic/keyring.py @@ -1,6 +1,5 @@ from datetime import datetime, timedelta, timezone from enum import Enum -from typing import Optional from sqlalchemy import insert, select, update from sqlalchemy.dialects.mysql import insert as mysql_insert @@ -11,7 +10,7 @@ from api.schemas.account.account_keyring import AccountKeyring from api.utils.hasher import hasher -async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[AccountKeyring]: +async def get_key_by_id(connection: AsyncConnection, key_id: str) -> AccountKeyring | None: """ Получает key по key_id. """ @@ -26,7 +25,7 @@ async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[Ac return AccountKeyring.model_validate(user_data) -async def update_key_by_id(connection: AsyncConnection, update_values, key) -> Optional[AccountKeyring]: +async def update_key_by_id(connection: AsyncConnection, update_values, key) -> AccountKeyring | None: """ Вносит изменеия в нужное поле таблицы account_keyring_table. """ @@ -37,7 +36,7 @@ async def update_key_by_id(connection: AsyncConnection, update_values, key) -> O await connection.commit() -async def create_key(connection: AsyncConnection, key: AccountKeyring, key_id: str) -> Optional[AccountKeyring]: +async def create_key(connection: AsyncConnection, key: AccountKeyring, key_id: str) -> AccountKeyring | None: """ Создает нове поле в таблице account_keyring_table). """ diff --git a/api/api/db/logic/list_events.py b/api/api/db/logic/list_events.py index b50cc00..15addd6 100644 --- a/api/api/db/logic/list_events.py +++ b/api/api/db/logic/list_events.py @@ -1,4 +1,3 @@ -from typing import Optional import math from datetime import datetime, timezone @@ -16,7 +15,7 @@ from api.schemas.endpoints.list_events import all_list_event_adapter, AllListEve async def get_list_events_page_DTO( connection: AsyncConnection, filter_dto: ListEventFilterDTO -) -> Optional[AllListEventResponse]: +) -> AllListEventResponse | None: """ Получает список событий с фильтрацией через DTO объект. Поддерживает: @@ -121,7 +120,7 @@ async def get_list_events_page_DTO( ) -async def get_list_events_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: +async def get_list_events_by_name(connection: AsyncConnection, name: str) -> ListEvent | None: """ Получает list events по name. """ @@ -136,7 +135,7 @@ async def get_list_events_by_name(connection: AsyncConnection, name: str) -> Opt return ListEvent.model_validate(list_events_data) -async def get_list_events_by_id(connection: AsyncConnection, id: int) -> Optional[ListEvent]: +async def get_list_events_by_id(connection: AsyncConnection, id: int) -> ListEvent | None: """ Получает listevent по id. """ @@ -162,9 +161,7 @@ async def update_list_events_by_id(connection: AsyncConnection, update_values, l await connection.commit() -async def create_list_events( - connection: AsyncConnection, list_events: ListEvent, creator_id: int -) -> Optional[ListEvent]: +async def create_list_events(connection: AsyncConnection, list_events: ListEvent, creator_id: int) -> ListEvent | None: """ Создает нове поле в таблице list_events_table. """ diff --git a/api/api/db/logic/node_link.py b/api/api/db/logic/node_link.py index ca8d9b3..e565169 100644 --- a/api/api/db/logic/node_link.py +++ b/api/api/db/logic/node_link.py @@ -1,5 +1,3 @@ -from typing import Optional, List - from datetime import datetime, timezone from sqlalchemy import insert, select, desc @@ -11,7 +9,7 @@ from orm.tables.process import ps_node_table, node_link_table from orm.tables.process import NodeLinkStatus -async def get_last_link_name_by_node_id(connection: AsyncConnection, ps_id: int) -> Optional[str]: +async def get_last_link_name_by_node_id(connection: AsyncConnection, ps_id: int) -> str | None: """ Получает link_name из последней записи node_link по ps_id. Находит все node_id в ps_node по ps_id, затем ищет связи в node_link @@ -32,7 +30,7 @@ async def get_last_link_name_by_node_id(connection: AsyncConnection, ps_id: int) async def get_last_node_link_by_creator_and_ps_id( connection: AsyncConnection, creator_id: int, node_link_id: int -) -> Optional[NodeLink]: +) -> NodeLink | None: """ Получает последнюю созданную node_link для данного создателя и процесса. """ @@ -59,7 +57,7 @@ async def create_node_link_schema( connection: AsyncConnection, validated_link_schema, creator_id: int, -) -> Optional[NodeLink]: +) -> NodeLink | None: """ Создает нове поле в таблице process_schema_table. """ @@ -81,7 +79,7 @@ async def create_node_link_schema( return await get_last_node_link_by_creator_and_ps_id(connection, creator_id, validated_link_schema.from_id) -async def get_all_node_links_by_next_node_ids(connection: AsyncConnection, next_node_ids: List[int]) -> List[NodeLink]: +async def get_all_node_links_by_next_node_ids(connection: AsyncConnection, next_node_ids: list[int]) -> list[NodeLink]: """ Получает все активные node_link для списка next_node_id одним запросом. """ diff --git a/api/api/db/logic/process_schema.py b/api/api/db/logic/process_schema.py index ec097e1..4d3eb28 100644 --- a/api/api/db/logic/process_schema.py +++ b/api/api/db/logic/process_schema.py @@ -1,4 +1,4 @@ -from typing import Optional, Dict, Any +from typing import Any import math from datetime import datetime, timezone @@ -19,7 +19,7 @@ from api.schemas.endpoints.process_schema import ( async def get_process_schema_page_DTO( connection: AsyncConnection, filter_dto: ProcessSchemaFilterDTO -) -> Optional[AllProcessSchemaResponse]: +) -> AllProcessSchemaResponse | None: """ Получает список схем процессов с комплексной фильтрацией через DTO объект. Поддерживает: @@ -115,7 +115,7 @@ async def get_process_schema_page_DTO( ) -async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]: +async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> ProcessSchema | None: """ Получает process_schema по id. """ @@ -143,7 +143,7 @@ async def update_process_schema_by_id(connection: AsyncConnection, update_values async def create_process_schema( connection: AsyncConnection, creator_id: int, title: str, description: str -) -> Optional[int]: +) -> int | None: """ Создает новое поле в таблице process_schema_table. """ diff --git a/api/api/db/logic/ps_node.py b/api/api/db/logic/ps_node.py index c77b860..83b7162 100644 --- a/api/api/db/logic/ps_node.py +++ b/api/api/db/logic/ps_node.py @@ -1,4 +1,4 @@ -from typing import Optional, List, Dict, Any +from typing import Any from datetime import datetime, timezone @@ -11,7 +11,7 @@ from api.schemas.process.ps_node import Ps_Node from orm.tables.process import NodeStatus -async def get_ps_node_by_id(connection: AsyncConnection, id: int) -> Optional[Ps_Node]: +async def get_ps_node_by_id(connection: AsyncConnection, id: int) -> Ps_Node | None: """ Получает process_schema по id. """ @@ -28,7 +28,7 @@ async def get_ps_node_by_id(connection: AsyncConnection, id: int) -> Optional[Ps async def get_last_ps_node_by_creator_and_ps_id( connection: AsyncConnection, creator_id: int, ps_id: int -) -> Optional[Ps_Node]: +) -> Ps_Node | None: """ Получает последнюю созданную ps_node для данного создателя и процесса. """ @@ -48,7 +48,7 @@ async def get_last_ps_node_by_creator_and_ps_id( return Ps_Node.model_validate(ps_node_data) -async def get_all_ps_nodes_by_ps_id(connection: AsyncConnection, ps_id: int) -> List[Ps_Node]: +async def get_all_ps_nodes_by_ps_id(connection: AsyncConnection, ps_id: int) -> list[Ps_Node]: """ Получает все активные ps_node для данной process_schema. """ @@ -67,8 +67,8 @@ async def create_ps_node_schema( validated_schema, node_descriptor, creator_id: int, - settings_payload: Optional[Dict[str, Any]] = None, -) -> Optional[Ps_Node]: + settings_payload: dict[str, Any] | None = None, +) -> Ps_Node | None: """ Создает нове поле в таблице process_schema_table. """ @@ -104,7 +104,7 @@ async def check_node_connection(connection: AsyncConnection, node_id: int, next_ return result.mappings().first() is not None -async def get_nodes_for_deletion_ordered(connection: AsyncConnection, node_id: int) -> List[int]: +async def get_nodes_for_deletion_ordered(connection: AsyncConnection, node_id: int) -> list[int]: """ Рекурсивно находит ВСЕ дочерние узлы и возвращает их ID в правильном порядке: от самых глубоких к корневым. @@ -144,7 +144,7 @@ async def get_nodes_for_deletion_ordered(connection: AsyncConnection, node_id: i return ordered_node_ids -async def delete_ps_nodes_delete_handler(connection: AsyncConnection, node_ids: List[int]) -> List[int]: +async def delete_ps_nodes_delete_handler(connection: AsyncConnection, node_ids: list[int]) -> list[int]: """ Очищает settings и удаляет ноды для каждого ps_id. Возвращает список успешно удаленных ID нод. @@ -177,7 +177,7 @@ async def delete_ps_nodes_delete_handler(connection: AsyncConnection, node_ids: return deleted_all -async def remove_nodes_from_process_schema_settings(connection: AsyncConnection, ps_id: int, node_ids: List[int]): +async def remove_nodes_from_process_schema_settings(connection: AsyncConnection, ps_id: int, node_ids: list[int]): """ Удаляет ноды из поля settings в таблице process_schema по списку node_ids. """ diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 46cbace..07eaeaf 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -1,5 +1,3 @@ -from typing import List, Optional - from fastapi import APIRouter, Depends, Query, status from sqlalchemy.ext.asyncio import AsyncConnection @@ -23,12 +21,12 @@ api_router = APIRouter( async def get_all_account_endpoint( page: int = Query(1, description="Page number", gt=0), limit: int = Query(10, description="КNumber of items per page", gt=0), - search: Optional[str] = Query(None, description="Search term to filter by name or login or email"), - status_filter: Optional[List[str]] = Query(None, description="Filter by status"), - role_filter: Optional[List[str]] = Query(None, description="Filter by role"), - creator_id: Optional[int] = Query(None, description="Filter by creator id"), - order_field: Optional[str] = Query("id", description="Field to sort by"), - order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), + search: str | None = Query(None, description="Search term to filter by name or login or email"), + status_filter: list[str] | None = Query(None, description="Filter by status"), + role_filter: list[str] | None = Query(None, description="Filter by role"), + creator_id: int | None = Query(None, description="Filter by creator id"), + order_field: str | None = Query("id", description="Field to sort by"), + order_direction: str | None = Query("asc", description="Sort direction (asc/desc)"), connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): diff --git a/api/api/endpoints/list_events.py b/api/api/endpoints/list_events.py index f00a1e7..5c1cfb9 100644 --- a/api/api/endpoints/list_events.py +++ b/api/api/endpoints/list_events.py @@ -1,5 +1,3 @@ -from typing import List, Optional - from fastapi import APIRouter, Depends, Query, status from sqlalchemy.ext.asyncio import AsyncConnection @@ -23,12 +21,12 @@ api_router = APIRouter( async def get_all_list_events_endpoint( page: int = Query(1, description="Page number", gt=0), limit: int = Query(10, description="Number of items per page", gt=0), - search: Optional[str] = Query(None, description="Search term to filter by title or name"), - order_field: Optional[str] = Query("id", description="Field to sort by"), - order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), - status_filter: Optional[List[str]] = Query(None, description="Filter by status"), - state_filter: Optional[List[str]] = Query(None, description="Filter by state"), - creator_id: Optional[int] = Query(None, description="Filter by creator id"), + search: str | None = Query(None, description="Search term to filter by title or name"), + order_field: str | None = Query("id", description="Field to sort by"), + order_direction: str | None = Query("asc", description="Sort direction (asc/desc)"), + status_filter: list[str] | None = Query(None, description="Filter by status"), + state_filter: list[str] | None = Query(None, description="Filter by state"), + creator_id: int | None = Query(None, description="Filter by creator id"), connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): diff --git a/api/api/endpoints/process_schema.py b/api/api/endpoints/process_schema.py index 741b217..d98024f 100644 --- a/api/api/endpoints/process_schema.py +++ b/api/api/endpoints/process_schema.py @@ -1,5 +1,3 @@ -from typing import List, Optional - from fastapi import APIRouter, Depends, Query, status, HTTPException from sqlalchemy.ext.asyncio import AsyncConnection @@ -25,14 +23,14 @@ api_router = APIRouter( async def get_all_process_schema_endpoint( page: int = Query(1, description="Page number", gt=0), limit: int = Query(10, description="Number of items per page", gt=0), - search: Optional[str] = Query(None, description="Search term to filter by title or description"), - order_field: Optional[str] = Query("id", description="Field to sort by"), - order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), - status_filter: Optional[List[str]] = Query(None, description="Filter by status"), - owner_id: Optional[List[str]] = Query(None, description="Filter by owner id"), + search: str | None = Query(None, description="Search term to filter by title or description"), + order_field: str | None = Query("id", description="Field to sort by"), + order_direction: str | None = Query("asc", description="Sort direction (asc/desc)"), + status_filter: list[str] | None = Query(None, description="Filter by status"), + owner_id: list[str] | None = Query(None, description="Filter by owner id"), show_deleted: bool = Query(False, description="Show only deleted schemas"), connection: AsyncConnection = Depends(get_connection_dep), - creator_id: Optional[int] = Query(None, description="Filter by creator id"), + creator_id: int | None = Query(None, description="Filter by creator id"), current_user=Depends(get_current_user), ): if show_deleted: diff --git a/api/api/error/error_handlers.py b/api/api/error/error_handlers.py index 8960f52..432487f 100644 --- a/api/api/error/error_handlers.py +++ b/api/api/error/error_handlers.py @@ -2,14 +2,14 @@ Обработчики ошибок для API. """ -from typing import Optional, Dict, Any +from typing import Any from fastapi import HTTPException from .error_model.error_types import ServerError, AccessError, OperationError, ValidationError, ErrorType def handle_api_error( - error_type: ErrorType, message: str, status_code: int, details: Optional[Dict[str, Any]] = None + error_type: ErrorType, message: str, status_code: int, details: dict[str, Any] | None = None ) -> HTTPException: """ Функция для создания HTTPException с правильной структурой ошибки. @@ -30,25 +30,21 @@ def handle_api_error( return HTTPException(status_code=status_code, detail=error.model_dump(mode="json")) -def create_server_error( - message: str, status_code: int = 500, details: Optional[Dict[str, Any]] = None -) -> HTTPException: +def create_server_error(message: str, status_code: int = 500, details: dict[str, Any] | None = None) -> HTTPException: return handle_api_error(error_type=ErrorType.SERVER, message=message, status_code=status_code, details=details) -def create_access_error( - message: str, status_code: int = 403, details: Optional[Dict[str, Any]] = None -) -> HTTPException: +def create_access_error(message: str, status_code: int = 403, details: dict[str, Any] | None = None) -> HTTPException: return handle_api_error(error_type=ErrorType.ACCESS, message=message, status_code=status_code, details=details) def create_operation_error( - message: str, status_code: int = 400, details: Optional[Dict[str, Any]] = None + message: str, status_code: int = 400, details: dict[str, Any] | None = None ) -> HTTPException: return handle_api_error(error_type=ErrorType.OPERATION, message=message, status_code=status_code, details=details) def create_validation_error( - message: str, status_code: int = 422, details: Optional[Dict[str, Any]] = None + message: str, status_code: int = 422, details: dict[str, Any] | None = None ) -> HTTPException: return handle_api_error(error_type=ErrorType.VALIDATION, message=message, status_code=status_code, details=details) diff --git a/api/api/error/error_model/error_types.py b/api/api/error/error_model/error_types.py index ee32422..9e820e4 100644 --- a/api/api/error/error_model/error_types.py +++ b/api/api/error/error_model/error_types.py @@ -3,7 +3,7 @@ """ from enum import Enum -from typing import Optional, Dict, Any +from typing import Any from pydantic import BaseModel @@ -25,7 +25,7 @@ class BaseError(BaseModel): error_type: ErrorType message: str - details: Optional[Dict[str, Any]] = None + details: dict[str, Any] | None = None class ServerError(BaseError): @@ -58,4 +58,4 @@ class ValidationError(BaseError): """ error_type: ErrorType = ErrorType.VALIDATION - field_errors: Optional[Dict[str, str]] = None + field_errors: dict[str, str] | None = None diff --git a/api/api/schemas/account/account.py b/api/api/schemas/account/account.py index f105c8d..7f6007c 100644 --- a/api/api/schemas/account/account.py +++ b/api/api/schemas/account/account.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import Optional from orm.tables.account import AccountRole, AccountStatus from pydantic import EmailStr, Field @@ -8,13 +7,13 @@ from api.schemas.base import Base class User(Base): - id: Optional[int] = None + id: int | None = None name: str = Field(..., max_length=100) login: str = Field(..., max_length=100) - email: Optional[EmailStr] = Field(None, max_length=100) # Электронная почта (может быть None) - bind_tenant_id: Optional[str] = Field(None, max_length=40) + email: EmailStr | None = Field(None, max_length=100) # Электронная почта (может быть None) + bind_tenant_id: str | None = Field(None, max_length=40) role: AccountRole meta: dict - creator_id: Optional[int] = None + creator_id: int | None = None created_at: datetime status: AccountStatus diff --git a/api/api/schemas/account/account_keyring.py b/api/api/schemas/account/account_keyring.py index 9c2ca27..f86d2df 100644 --- a/api/api/schemas/account/account_keyring.py +++ b/api/api/schemas/account/account_keyring.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import Optional from orm.tables.account import KeyStatus, KeyType from pydantic import Field @@ -10,8 +9,8 @@ from api.schemas.base import Base class AccountKeyring(Base): owner_id: int key_type: KeyType - key_id: Optional[str] = Field(None, max_length=40) + key_id: str | None = Field(None, max_length=40) key_value: str = Field(..., max_length=255) created_at: datetime - expiry: Optional[datetime] = None + expiry: datetime | None = None status: KeyStatus diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index 8965f1e..82b9ad9 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import Dict, List, Optional from orm.tables.account import AccountRole, AccountStatus from pydantic import EmailStr, Field, TypeAdapter @@ -8,24 +7,24 @@ from api.schemas.base import Base class UserUpdate(Base): - name: Optional[str] = Field(None, max_length=100) - login: Optional[str] = Field(None, max_length=100) - email: Optional[EmailStr] = None - password: Optional[str] = None - bind_tenant_id: Optional[str] = Field(None, max_length=40) - role: Optional[AccountRole] = None - meta: Optional[dict] = None - status: Optional[AccountStatus] = None + name: str | None = Field(None, max_length=100) + login: str | None = Field(None, max_length=100) + email: EmailStr | None = None + password: str | None = None + bind_tenant_id: str | None = Field(None, max_length=40) + role: AccountRole | None = None + meta: dict | None = None + status: AccountStatus | None = None class UserCreate(Base): name: str = Field(max_length=100) login: str = Field(max_length=100) - email: Optional[EmailStr] = None - password: Optional[str] = None - bind_tenant_id: Optional[str] = Field(None, max_length=40) + email: EmailStr | None = None + password: str | None = None + bind_tenant_id: str | None = Field(None, max_length=40) role: AccountRole - meta: Optional[dict] = None + meta: dict | None = None status: AccountStatus @@ -33,28 +32,28 @@ class AllUser(Base): id: int name: str login: str - email: Optional[EmailStr] = None - bind_tenant_id: Optional[str] = None + email: EmailStr | None = None + bind_tenant_id: str | None = None role: AccountRole - meta: Optional[dict] = None - creator_id: Optional[int] = None + meta: dict | None = None + creator_id: int | None = None created_at: datetime status: AccountStatus class AllUserResponse(Base): - users: List[AllUser] + users: list[AllUser] amount_count: int amount_pages: int current_page: int limit: int -all_user_adapter = TypeAdapter(List[AllUser]) +all_user_adapter = TypeAdapter(list[AllUser]) class UserFilterDTO(Base): - pagination: Dict[str, int] - search: Optional[str] = None - order: Optional[Dict[str, str]] = None - filters: Optional[Dict[str, List[str]]] = None + pagination: dict[str, int] + search: str | None = None + order: dict[str, str] | None = None + filters: dict[str, list[str]] | None = None diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index 78728fc..e4ee17c 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -1,5 +1,3 @@ -from typing import Optional - from orm.tables.account import KeyStatus, KeyType from pydantic import Field @@ -7,7 +5,7 @@ from api.schemas.base import Base class AccountKeyringUpdate(Base): - owner_id: Optional[int] = None - key_type: Optional[KeyType] = None - key_value: Optional[str] = Field(None, max_length=255) - status: Optional[KeyStatus] = None + owner_id: int | None = None + key_type: KeyType | None = None + key_value: str | None = Field(None, max_length=255) + status: KeyStatus | None = None diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 4943f11..b6e702e 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict, List, Optional +from typing import Any from orm.tables.events import EventState, EventStatus from pydantic import Field, TypeAdapter @@ -8,11 +8,11 @@ from api.schemas.base import Base class ListEventUpdate(Base): - name: Optional[str] = Field(None, max_length=40) - title: Optional[str] = Field(None, max_length=64) - schema_: Optional[Dict[str, Any]] = Field(None, alias="schema") - state: Optional[EventState] = None - status: Optional[EventStatus] = None + name: str | None = Field(None, max_length=40) + title: str | None = Field(None, max_length=64) + schema_: dict[str, Any] | None = Field(None, alias="schema") + state: EventState | None = None + status: EventStatus | None = None class AllListEvent(Base): @@ -21,24 +21,24 @@ class AllListEvent(Base): title: str creator_id: int created_at: datetime - schema_: Dict[str, Any] = Field(default={}, alias="schema") + schema_: dict[str, Any] = Field(default={}, alias="schema") state: EventState status: EventStatus class AllListEventResponse(Base): - list_event: List[AllListEvent] + list_event: list[AllListEvent] amount_count: int amount_pages: int current_page: int limit: int -all_list_event_adapter = TypeAdapter(List[AllListEvent]) +all_list_event_adapter = TypeAdapter(list[AllListEvent]) class ListEventFilterDTO(Base): - pagination: Dict[str, int] - search: Optional[str] = None - order: Optional[Dict[str, str]] = None - filters: Optional[Dict[str, List[str]]] = None + pagination: dict[str, int] + search: str | None = None + order: dict[str, str] | None = None + filters: dict[str, list[str]] | None = None diff --git a/api/api/schemas/endpoints/process_schema.py b/api/api/schemas/endpoints/process_schema.py index 9dc41c8..a1615fc 100644 --- a/api/api/schemas/endpoints/process_schema.py +++ b/api/api/schemas/endpoints/process_schema.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict, List, Optional +from typing import Any from orm.tables.process import ProcessStatus from pydantic import Field, TypeAdapter @@ -8,11 +8,11 @@ from api.schemas.base import Base class ProcessSchemaUpdate(Base): - title: Optional[str] = Field(None, max_length=100) - description: Optional[str] = None - # owner_id: Optional[int] = None - settings: Optional[Dict[str, Any]] = None - status: Optional[ProcessStatus] = None + title: str | None = Field(None, max_length=100) + description: str | None = None + # owner_id: int | None = None + settings: dict[str, Any] | None = None + status: ProcessStatus | None = None class AllProcessSchema(Base): @@ -22,23 +22,23 @@ class AllProcessSchema(Base): owner_id: int creator_id: int created_at: datetime - settings: Dict[str, Any] + settings: dict[str, Any] status: ProcessStatus class AllProcessSchemaResponse(Base): - process_schema: List[AllProcessSchema] + process_schema: list[AllProcessSchema] amount_count: int amount_pages: int current_page: int limit: int -all_process_schema_adapter = TypeAdapter(List[AllProcessSchema]) +all_process_schema_adapter = TypeAdapter(list[AllProcessSchema]) class ProcessSchemaFilterDTO(Base): - pagination: Dict[str, int] - search: Optional[str] = None - order: Optional[Dict[str, str]] = None - filters: Optional[Dict[str, List[str]]] = None + pagination: dict[str, int] + search: str | None = None + order: dict[str, str] | None = None + filters: dict[str, list[str]] | None = None diff --git a/api/api/schemas/events/list_events.py b/api/api/schemas/events/list_events.py index 7c0245d..f22733b 100644 --- a/api/api/schemas/events/list_events.py +++ b/api/api/schemas/events/list_events.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict +from typing import Any from orm.tables.events import EventState, EventStatus from pydantic import Field @@ -13,6 +13,6 @@ class ListEvent(Base): title: str = Field(..., max_length=64) creator_id: int created_at: datetime - schema_: Dict[str, Any] = Field(..., alias="schema") + schema_: dict[str, Any] = Field(..., alias="schema") state: EventState status: EventStatus diff --git a/api/api/schemas/process/node_link.py b/api/api/schemas/process/node_link.py index ea3b03f..d8d9d85 100644 --- a/api/api/schemas/process/node_link.py +++ b/api/api/schemas/process/node_link.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict +from typing import Any from orm.tables.process import NodeStatus from pydantic import Field @@ -13,7 +13,7 @@ class NodeLink(Base): node_id: int link_point_id: int next_node_id: int - settings: Dict[str, Any] + settings: dict[str, Any] creator_id: int created_at: datetime status: NodeStatus diff --git a/api/api/schemas/process/process_schema.py b/api/api/schemas/process/process_schema.py index 65254fe..f43915b 100644 --- a/api/api/schemas/process/process_schema.py +++ b/api/api/schemas/process/process_schema.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict, List +from typing import Any from orm.tables.process import ProcessStatus from pydantic import Field @@ -15,10 +15,10 @@ class ProcessSchema(Base): owner_id: int creator_id: int created_at: datetime - settings: Dict[str, Any] + settings: dict[str, Any] status: ProcessStatus class ProcessSchemaResponse(Base): process_schema: ProcessSchema - nodes: List[Ps_NodeFrontResponse] + nodes: list[Ps_NodeFrontResponse] diff --git a/api/api/schemas/process/ps_node.py b/api/api/schemas/process/ps_node.py index 0722d9a..15b72b8 100644 --- a/api/api/schemas/process/ps_node.py +++ b/api/api/schemas/process/ps_node.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, Dict, Optional, List +from typing import Any from orm.tables.process import NodeStatus, NodeType @@ -14,8 +14,8 @@ class Ps_NodeDeleteRequest(Base): class Ps_NodeRequest(Base): - data: Dict[str, Any] - links: Dict[str, Any] + data: dict[str, Any] + links: dict[str, Any] class Ps_Node(Base): @@ -29,5 +29,5 @@ class Ps_Node(Base): class Ps_NodeFrontResponse(Base): - node: Optional[Dict[str, Any]] = None - link: Optional[List[Dict[str, Any]]] = None + node: dict[str, Any] | None = None + link: list[dict[str, Any]] | None = None diff --git a/api/api/services/auth.py b/api/api/services/auth.py index d462602..cde2b13 100644 --- a/api/api/services/auth.py +++ b/api/api/services/auth.py @@ -1,5 +1,3 @@ -from typing import Optional - from fastapi import HTTPException, Request from orm.tables.account import AccountStatus from sqlalchemy.ext.asyncio import AsyncConnection @@ -15,7 +13,7 @@ async def get_current_user(request: Request) -> str | HTTPException: return request.state.current_user -async def authenticate_user(connection: AsyncConnection, username: str, password: str) -> Optional[AllUser]: +async def authenticate_user(connection: AsyncConnection, username: str, password: str) -> AllUser | None: sql_user, sql_password = await get_user(connection, username) if not sql_user or sql_user.status != AccountStatus.ACTIVE: diff --git a/api/api/services/endpoints/account.py b/api/api/services/endpoints/account.py index 21c6f37..6f54b41 100644 --- a/api/api/services/endpoints/account.py +++ b/api/api/services/endpoints/account.py @@ -1,4 +1,3 @@ -from typing import Optional from sqlalchemy.ext.asyncio import AsyncConnection from orm.tables.account import AccountStatus @@ -19,13 +18,13 @@ class AccountService: def __init__(self, connection: AsyncConnection): self.connection = connection - async def list(self, filter_dto: UserFilterDTO) -> Optional[AllUserResponse]: + async def list(self, filter_dto: UserFilterDTO) -> AllUserResponse | None: """ Получает список пользователей с пагинацией и фильтрацией. """ return await get_user_account_page_DTO(self.connection, filter_dto) - async def get(self, user_id: int) -> Optional[User]: + async def get(self, user_id: int) -> User | None: """ Получает пользователя по ID. """ diff --git a/api/api/services/endpoints/keyring.py b/api/api/services/endpoints/keyring.py index f2094d0..3c5251e 100644 --- a/api/api/services/endpoints/keyring.py +++ b/api/api/services/endpoints/keyring.py @@ -1,4 +1,3 @@ -from typing import Optional from sqlalchemy.ext.asyncio import AsyncConnection from orm.tables.account import KeyStatus @@ -15,7 +14,7 @@ class KeyringService: def __init__(self, connection: AsyncConnection): self.connection = connection - async def get(self, key_id: str) -> Optional[AccountKeyring]: + async def get(self, key_id: str) -> AccountKeyring | None: """ Получает keyring по key_id. """ diff --git a/api/api/services/endpoints/list_events.py b/api/api/services/endpoints/list_events.py index 2d80cbc..a199888 100644 --- a/api/api/services/endpoints/list_events.py +++ b/api/api/services/endpoints/list_events.py @@ -1,4 +1,3 @@ -from typing import Optional from sqlalchemy.ext.asyncio import AsyncConnection from orm.tables.events import EventStatus @@ -19,25 +18,25 @@ class ListEventsService: def __init__(self, connection: AsyncConnection): self.connection = connection - async def list(self, filter_dto: ListEventFilterDTO) -> Optional[AllListEventResponse]: + async def list(self, filter_dto: ListEventFilterDTO) -> AllListEventResponse | None: """ Получает список событий с пагинацией и фильтрацией. """ return await get_list_events_page_DTO(self.connection, filter_dto) - async def get(self, list_events_id: int) -> Optional[ListEvent]: + async def get(self, list_events_id: int) -> ListEvent | None: """ Получает событие по ID. """ return await get_list_events_by_id(self.connection, list_events_id) - async def get_by_name(self, name: str) -> Optional[ListEvent]: + async def get_by_name(self, name: str) -> ListEvent | None: """ Получает событие по name. """ return await get_list_events_by_name(self.connection, name) - async def create(self, list_events_data: ListEventUpdate, creator_id: int) -> Optional[ListEvent]: + async def create(self, list_events_data: ListEventUpdate, creator_id: int) -> ListEvent | None: """ Создаёт новое событие. """ diff --git a/api/api/services/endpoints/process_schema.py b/api/api/services/endpoints/process_schema.py index 749ebaa..8d69e61 100644 --- a/api/api/services/endpoints/process_schema.py +++ b/api/api/services/endpoints/process_schema.py @@ -1,4 +1,4 @@ -from typing import Optional, Dict, Any +from typing import Any from sqlalchemy.ext.asyncio import AsyncConnection from orm.tables.process import ProcessStatus @@ -25,13 +25,13 @@ class ProcessSchemaService: def __init__(self, connection: AsyncConnection): self.connection = connection - async def list(self, filter_dto: ProcessSchemaFilterDTO) -> Optional[AllProcessSchemaResponse]: + async def list(self, filter_dto: ProcessSchemaFilterDTO) -> AllProcessSchemaResponse | None: """ Получает список схем процессов с пагинацией и фильтрацией. """ return await get_process_schema_page_DTO(self.connection, filter_dto) - async def get(self, process_schema_id: int) -> Optional[ProcessSchemaResponse]: + async def get(self, process_schema_id: int) -> ProcessSchemaResponse | None: """ Получает схему процесса по ID со всеми нодами и линками. """ @@ -66,7 +66,7 @@ class ProcessSchemaService: nodes=nodes_response, ) - async def create(self, creator_id: int) -> Dict[str, Any]: + async def create(self, creator_id: int) -> dict[str, Any]: """ Создаёт новую схему процесса с начальной нодой LISTEN. """ diff --git a/api/api/services/endpoints/profile.py b/api/api/services/endpoints/profile.py index a98d45f..8c506d7 100644 --- a/api/api/services/endpoints/profile.py +++ b/api/api/services/endpoints/profile.py @@ -1,4 +1,3 @@ -from typing import Optional from sqlalchemy.ext.asyncio import AsyncConnection from api.db.logic.account import get_user_by_id, get_user_by_login, update_user_by_id @@ -11,7 +10,7 @@ class ProfileService: def __init__(self, connection: AsyncConnection): self.connection = connection - async def get_by_login(self, login: str) -> Optional[User]: + async def get_by_login(self, login: str) -> User | None: """ Получает пользователя по логину. """ diff --git a/api/api/services/endpoints/ps_node.py b/api/api/services/endpoints/ps_node.py index 260afb7..91edd97 100644 --- a/api/api/services/endpoints/ps_node.py +++ b/api/api/services/endpoints/ps_node.py @@ -1,4 +1,4 @@ -from typing import List, Dict, Any +from typing import Any from sqlalchemy.ext.asyncio import AsyncConnection from api.db.logic.ps_node import ( @@ -18,7 +18,7 @@ class PsNodeService: def __init__(self, connection: AsyncConnection): self.connection = connection - async def delete(self, next_node_id: int) -> Dict[str, List[int]]: + async def delete(self, next_node_id: int) -> dict[str, list[int]]: """ Удаляет ноды в правильном порядке. """ @@ -30,7 +30,7 @@ class PsNodeService: } async def create( - self, ps_node_data: Dict[str, Any], links: Dict[str, Any], creator_id: int + self, ps_node_data: dict[str, Any], links: dict[str, Any], creator_id: int ) -> Ps_NodeFrontResponse: """ Создаёт новую ноду с линком и обновляет настройки схемы процесса. diff --git a/api/api/utils/node_counter.py b/api/api/utils/node_counter.py index 63aecba..5d3e72d 100644 --- a/api/api/utils/node_counter.py +++ b/api/api/utils/node_counter.py @@ -1,6 +1,5 @@ import json from pathlib import Path -from typing import Dict # Путь к файлу счётчика (в корне проекта) @@ -17,7 +16,7 @@ def get_node_counter() -> int: """ if not COUNTER_FILE_PATH.exists(): - initial_data: Dict[str, int] = {"node_counter": 0} + initial_data: dict[str, int] = {"node_counter": 0} with open(COUNTER_FILE_PATH, "w", encoding="utf-8") as f: json.dump(initial_data, f, indent=2, ensure_ascii=False) return 0 @@ -45,7 +44,7 @@ def increment_node_counter() -> int: new_value = current_value + 1 - data: Dict[str, int] = {"node_counter": new_value} + data: dict[str, int] = {"node_counter": new_value} with open(COUNTER_FILE_PATH, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) -- 2.39.5 From c86b7eb624b27cb677239a843d89b71f4e402d2b Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Mon, 24 Nov 2025 22:02:34 +0700 Subject: [PATCH 3/3] fix: delete port checks --- api/api/endpoints/ps_node.py | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/api/api/endpoints/ps_node.py b/api/api/endpoints/ps_node.py index 4f8fb2a..df2b007 100644 --- a/api/api/endpoints/ps_node.py +++ b/api/api/endpoints/ps_node.py @@ -61,21 +61,6 @@ async def delete_ps_node_endpoint( details={"next_node_id": ps_node_delete_data.next_node_id}, ) - # is_connected = await check_node_connection( - # connection, ps_node_delete_data.node_id, ps_node_delete_data.next_node_id, int(ps_node_delete_data.port) - # ) - - # if not is_connected: - # raise create_validation_error( - # message="Node connection validation failed", - # status_code=status.HTTP_400_BAD_REQUEST, - # details={ - # "node_id": ps_node_delete_data.node_id, - # "next_node_id": ps_node_delete_data.next_node_id, - # "port": ps_node_delete_data.port, - # }, - # ) - service = PsNodeService(connection) try: result = await service.delete(ps_node_delete_data.next_node_id) @@ -153,22 +138,6 @@ async def create_ps_node_endpoint( details={"parent_id": parent_id, "expected_ps_id": target_ps_id, "actual_ps_id": parent_node.ps_id}, ) - # parent_port_number = node_instance_validated.parent_port_number - - # parent_settings = parent_node.settings or {} - # available_port_numbers = [] - - # for key, value in parent_settings.items(): - # if "port" in key.lower() and isinstance(value, int): - # available_port_numbers.append(value) - - # if parent_port_number not in available_port_numbers: - # raise create_validation_error( - # message="Parent port number is invalid", - # status_code=status.HTTP_400_BAD_REQUEST, - # details={"parent_id": parent_id, "parent_settings": parent_settings}, - # ) - service = PsNodeService(connection) try: ps_node_front_response = await service.create(ps_node.data, ps_node.links, user_validation.id) -- 2.39.5