feat: CRUD process schema #19
@@ -0,0 +1,7 @@
 | 
			
		||||
from sqlalchemy import MetaData
 | 
			
		||||
 | 
			
		||||
metadata = MetaData()
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    "metadata",
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								api/api/db/alembic/versions/816be8c60ab4_.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								api/api/db/alembic/versions/816be8c60ab4_.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
"""empty message
 | 
			
		||||
 | 
			
		||||
Revision ID: 816be8c60ab4
 | 
			
		||||
Revises: 93106fbe7d83
 | 
			
		||||
Create Date: 2025-09-12 14:48:47.726269
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from typing import Sequence, Union
 | 
			
		||||
 | 
			
		||||
from alembic import op
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
from sqlalchemy.dialects import mysql
 | 
			
		||||
 | 
			
		||||
# revision identifiers, used by Alembic.
 | 
			
		||||
revision: str = '816be8c60ab4'
 | 
			
		||||
down_revision: Union[str, None] = '93106fbe7d83'
 | 
			
		||||
branch_labels: Union[str, Sequence[str], None] = None
 | 
			
		||||
depends_on: Union[str, Sequence[str], None] = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgrade() -> None:
 | 
			
		||||
    """Upgrade schema."""
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.alter_column('ps_node', 'node_type',
 | 
			
		||||
               existing_type=mysql.ENUM('TYPE1', 'TYPE2', 'TYPE3'),
 | 
			
		||||
               type_=sa.Enum('LISTEN', 'IF', 'START', name='nodetype'),
 | 
			
		||||
               existing_nullable=False)
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downgrade() -> None:
 | 
			
		||||
    """Downgrade schema."""
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.alter_column('ps_node', 'node_type',
 | 
			
		||||
               existing_type=sa.Enum('LISTEN', 'IF', 'START', name='nodetype'),
 | 
			
		||||
               type_=mysql.ENUM('TYPE1', 'TYPE2', 'TYPE3'),
 | 
			
		||||
               existing_nullable=False)
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
"""update node_link_table link_point_id default
 | 
			
		||||
 | 
			
		||||
Revision ID: cc3b95f1f99d
 | 
			
		||||
Revises: 816be8c60ab4
 | 
			
		||||
Create Date: 2025-09-12 19:17:03.125276
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from typing import Sequence, Union
 | 
			
		||||
 | 
			
		||||
from alembic import op
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
from sqlalchemy.dialects import mysql
 | 
			
		||||
 | 
			
		||||
# revision identifiers, used by Alembic.
 | 
			
		||||
revision: str = 'cc3b95f1f99d'
 | 
			
		||||
down_revision: Union[str, None] = '816be8c60ab4'
 | 
			
		||||
branch_labels: Union[str, Sequence[str], None] = None
 | 
			
		||||
depends_on: Union[str, Sequence[str], None] = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgrade() -> None:
 | 
			
		||||
    """Upgrade schema."""
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.add_column('node_link', sa.Column('link_point_id', sa.Integer().with_variant(mysql.INTEGER(unsigned=True), 'mysql'), nullable=False))
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downgrade() -> None:
 | 
			
		||||
    """Downgrade schema."""
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    op.drop_column('node_link', 'link_point_id')
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
							
								
								
									
										81
									
								
								api/api/db/logic/node_link.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								api/api/db/logic/node_link.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
from typing import Optional
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timezone
 | 
			
		||||
 | 
			
		||||
from sqlalchemy import insert, select, desc
 | 
			
		||||
from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
 | 
			
		||||
from api.schemas.process.node_link import NodeLink
 | 
			
		||||
 | 
			
		||||
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]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает link_name из последней записи node_link по ps_id.
 | 
			
		||||
    Находит все node_id в ps_node по ps_id, затем ищет связи в node_link
 | 
			
		||||
    и возвращает link_name из самой последней записи.
 | 
			
		||||
    """
 | 
			
		||||
    query = (
 | 
			
		||||
        select(node_link_table.c.link_name)
 | 
			
		||||
        .where(node_link_table.c.node_id.in_(select(ps_node_table.c.id).where(ps_node_table.c.ps_id == ps_id)))
 | 
			
		||||
        .order_by(desc(node_link_table.c.created_at))
 | 
			
		||||
        .limit(1)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    result = await connection.execute(query)
 | 
			
		||||
    link_name = result.scalar_one_or_none()
 | 
			
		||||
 | 
			
		||||
    return link_name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_last_node_link_by_creator_and_ps_id(
 | 
			
		||||
    connection: AsyncConnection, creator_id: int, node_link_id: int
 | 
			
		||||
) -> Optional[NodeLink]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает последнюю созданную node_link для данного создателя и процесса.
 | 
			
		||||
    """
 | 
			
		||||
    query = (
 | 
			
		||||
        select(node_link_table)
 | 
			
		||||
        .where(
 | 
			
		||||
            node_link_table.c.creator_id == creator_id,
 | 
			
		||||
            node_link_table.c.node_id.in_(select(ps_node_table.c.id).where(ps_node_table.c.id == node_link_id)),
 | 
			
		||||
        )
 | 
			
		||||
        .order_by(desc(node_link_table.c.created_at))
 | 
			
		||||
        .limit(1)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    node_link_db_cursor = await connection.execute(query)
 | 
			
		||||
    node_link_data = node_link_db_cursor.mappings().one_or_none()
 | 
			
		||||
 | 
			
		||||
    if not node_link_data:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    return NodeLink.model_validate(node_link_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def create_node_link_schema(
 | 
			
		||||
    connection: AsyncConnection,
 | 
			
		||||
    validated_link_schema,
 | 
			
		||||
    creator_id: int,
 | 
			
		||||
) -> Optional[NodeLink]:
 | 
			
		||||
    """
 | 
			
		||||
    Создает нове поле в таблице process_schema_table.
 | 
			
		||||
    """
 | 
			
		||||
    query = insert(node_link_table).values(
 | 
			
		||||
        link_name=validated_link_schema.link_name,
 | 
			
		||||
        node_id=validated_link_schema.from_id,
 | 
			
		||||
        link_point_id=validated_link_schema.parent_port_number,
 | 
			
		||||
        next_node_id=validated_link_schema.to_id,
 | 
			
		||||
        settings={},
 | 
			
		||||
        creator_id=creator_id,
 | 
			
		||||
        created_at=datetime.now(timezone.utc),
 | 
			
		||||
        status=NodeLinkStatus.ACTIVE.value,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    await connection.execute(query)
 | 
			
		||||
 | 
			
		||||
    await connection.commit()
 | 
			
		||||
 | 
			
		||||
    return await get_last_node_link_by_creator_and_ps_id(connection, creator_id, validated_link_schema.from_id)
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from typing import Optional, Dict, Any
 | 
			
		||||
import math
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timezone
 | 
			
		||||
@@ -6,7 +6,7 @@ from datetime import datetime, timezone
 | 
			
		||||
from sqlalchemy import insert, select, func, or_, and_, asc, desc
 | 
			
		||||
from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
 | 
			
		||||
from orm.tables.process import process_schema_table
 | 
			
		||||
from orm.tables.process import process_schema_table, ProcessStatus
 | 
			
		||||
 | 
			
		||||
from api.schemas.process.process_schema import ProcessSchema
 | 
			
		||||
 | 
			
		||||
@@ -50,8 +50,9 @@ async def get_process_schema_page_DTO(
 | 
			
		||||
            or_(process_schema_table.c.title.ilike(search_term), process_schema_table.c.description.ilike(search_term))
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    filter_conditions = []
 | 
			
		||||
 | 
			
		||||
    if filter_dto.filters:
 | 
			
		||||
        filter_conditions = []
 | 
			
		||||
        for field, values in filter_dto.filters.items():
 | 
			
		||||
            column = getattr(process_schema_table.c, field, None)
 | 
			
		||||
            if column is not None and values:
 | 
			
		||||
@@ -60,8 +61,11 @@ async def get_process_schema_page_DTO(
 | 
			
		||||
                else:
 | 
			
		||||
                    filter_conditions.append(column.in_(values))
 | 
			
		||||
 | 
			
		||||
        if filter_conditions:
 | 
			
		||||
            query = query.where(and_(*filter_conditions))
 | 
			
		||||
    if filter_dto.filters is None or "status" not in filter_dto.filters:
 | 
			
		||||
        filter_conditions.append(process_schema_table.c.status != "DELETED")
 | 
			
		||||
 | 
			
		||||
    if filter_conditions:
 | 
			
		||||
        query = query.where(and_(*filter_conditions))
 | 
			
		||||
 | 
			
		||||
    if filter_dto.order:
 | 
			
		||||
        order_field = filter_dto.order.get("field", "id")
 | 
			
		||||
@@ -86,7 +90,7 @@ async def get_process_schema_page_DTO(
 | 
			
		||||
            or_(process_schema_table.c.title.ilike(search_term), process_schema_table.c.description.ilike(search_term))
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    if filter_dto.filters and filter_conditions:
 | 
			
		||||
    if filter_conditions:
 | 
			
		||||
        count_query = count_query.where(and_(*filter_conditions))
 | 
			
		||||
 | 
			
		||||
    result = await connection.execute(query)
 | 
			
		||||
@@ -110,22 +114,6 @@ async def get_process_schema_page_DTO(
 | 
			
		||||
        limit=limit,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_process_schema_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает process schema  по title.
 | 
			
		||||
    """
 | 
			
		||||
    query = select(process_schema_table).where(process_schema_table.c.title == title)
 | 
			
		||||
 | 
			
		||||
    process_schema_db_cursor = await connection.execute(query)
 | 
			
		||||
 | 
			
		||||
    process_schema_data = process_schema_db_cursor.mappings().one_or_none()
 | 
			
		||||
    if not process_schema_data:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    return ProcessSchema.model_validate(process_schema_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает process_schema по id.
 | 
			
		||||
@@ -152,24 +140,68 @@ async def update_process_schema_by_id(connection: AsyncConnection, update_values
 | 
			
		||||
    await connection.commit()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def create_process_schema(
 | 
			
		||||
    connection: AsyncConnection, process_schema: ProcessSchema, creator_id: int
 | 
			
		||||
) -> Optional[ProcessSchema]:
 | 
			
		||||
async def update_process_schema_settings_by_id(
 | 
			
		||||
    connection: AsyncConnection, process_schema_id: int, node_data: Dict[str, Any]
 | 
			
		||||
):
 | 
			
		||||
    """
 | 
			
		||||
    Создает нове поле в таблице process_schema_table.
 | 
			
		||||
    Добавляет новый узел в массив 'nodes' в настройках процесса.
 | 
			
		||||
    Если массив 'nodes' не существует, создает его.
 | 
			
		||||
    """
 | 
			
		||||
    query = insert(process_schema_table).values(
 | 
			
		||||
        title=process_schema.title,
 | 
			
		||||
        description=process_schema.description,
 | 
			
		||||
        owner_id=process_schema.owner_id,
 | 
			
		||||
        creator_id=creator_id,
 | 
			
		||||
        created_at=datetime.now(timezone.utc),
 | 
			
		||||
        settings=process_schema.settings,
 | 
			
		||||
        status=process_schema.status.value,
 | 
			
		||||
    )
 | 
			
		||||
    # Получаем текущие 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()
 | 
			
		||||
 | 
			
		||||
    await connection.execute(query)
 | 
			
		||||
    # Если 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()
 | 
			
		||||
 | 
			
		||||
    return process_schema
 | 
			
		||||
 | 
			
		||||
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]:
 | 
			
		||||
    """
 | 
			
		||||
    Создает новое поле в таблице process_schema_table.
 | 
			
		||||
    """
 | 
			
		||||
    query = insert(process_schema_table).values(
 | 
			
		||||
        title=title,
 | 
			
		||||
        description=description,
 | 
			
		||||
        owner_id=creator_id,
 | 
			
		||||
        creator_id=creator_id,
 | 
			
		||||
        created_at=datetime.now(timezone.utc),
 | 
			
		||||
        settings={},
 | 
			
		||||
        status=ProcessStatus.ACTIVE.value,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    result = await connection.execute(query)
 | 
			
		||||
    await connection.commit()
 | 
			
		||||
 | 
			
		||||
    return result.lastrowid
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								api/api/db/logic/ps_node.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								api/api/db/logic/ps_node.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
from typing import Optional
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timezone
 | 
			
		||||
 | 
			
		||||
from sqlalchemy import insert, select, desc
 | 
			
		||||
from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
 | 
			
		||||
from orm.tables.process import ps_node_table
 | 
			
		||||
 | 
			
		||||
from api.schemas.process.ps_node import Ps_Node
 | 
			
		||||
from model_nodes.node_listen_models import ListenNodeCoreSchema
 | 
			
		||||
from orm.tables.process import NodeStatus, NodeType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_ps_node_by_id(connection: AsyncConnection, id: int) -> Optional[Ps_Node]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает process_schema по id.
 | 
			
		||||
    """
 | 
			
		||||
    query = select(ps_node_table).where(ps_node_table.c.id == id)
 | 
			
		||||
 | 
			
		||||
    ps_node_db_cursor = await connection.execute(query)
 | 
			
		||||
 | 
			
		||||
    ps_node_data = ps_node_db_cursor.mappings().one_or_none()
 | 
			
		||||
    if not ps_node_data:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    return Ps_Node.model_validate(ps_node_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_ps_node_by_type_and_ps_id(connection: AsyncConnection, node_type: str, ps_id: int) -> Optional[Ps_Node]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает ps_node по node_type и ps_id.
 | 
			
		||||
    """
 | 
			
		||||
    query = select(ps_node_table).where(ps_node_table.c.node_type == node_type, ps_node_table.c.ps_id == ps_id)
 | 
			
		||||
 | 
			
		||||
    ps_node_db_cursor = await connection.execute(query)
 | 
			
		||||
 | 
			
		||||
    ps_node_data = ps_node_db_cursor.mappings().one_or_none()
 | 
			
		||||
    if not ps_node_data:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    return Ps_Node.model_validate(ps_node_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_last_ps_node_by_creator_and_ps_id(
 | 
			
		||||
| 
					
	
	
	
	
	
	
	
	 
					
					ivan.dev marked this conversation as resolved
					
				 
				 | 
			||||
    connection: AsyncConnection, creator_id: int, ps_id: int
 | 
			
		||||
) -> Optional[Ps_Node]:
 | 
			
		||||
    """
 | 
			
		||||
    Получает последнюю созданную ps_node для данного создателя и процесса.
 | 
			
		||||
    """
 | 
			
		||||
    query = (
 | 
			
		||||
        select(ps_node_table)
 | 
			
		||||
        .where(ps_node_table.c.creator_id == creator_id, ps_node_table.c.ps_id == ps_id)
 | 
			
		||||
        .order_by(desc(ps_node_table.c.created_at))
 | 
			
		||||
        .limit(1)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    ps_node_db_cursor = await connection.execute(query)
 | 
			
		||||
    ps_node_data = ps_node_db_cursor.mappings().one_or_none()
 | 
			
		||||
 | 
			
		||||
    if not ps_node_data:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    return Ps_Node.model_validate(ps_node_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def create_ps_node_schema(
 | 
			
		||||
| 
					
	
	
	
	
	
	
	
	 
					
					ivan.dev marked this conversation as resolved
					
				 
				
				
					
						cyrussmeat
						commented  
			
		Это ты эмулируешь last_insert_id = await database.execute(query) ? Это ты эмулируешь last_insert_id = await database.execute(query) ? 
			
			
		 | 
			||||
    connection: AsyncConnection,
 | 
			
		||||
    validated_schema,
 | 
			
		||||
    creator_id: int,
 | 
			
		||||
) -> Optional[ListenNodeCoreSchema]:
 | 
			
		||||
    """
 | 
			
		||||
    Создает нове поле в таблице 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(),
 | 
			
		||||
        creator_id=creator_id,
 | 
			
		||||
        created_at=datetime.now(timezone.utc),
 | 
			
		||||
        status=NodeStatus.ACTIVE.value,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    await connection.execute(query)
 | 
			
		||||
 | 
			
		||||
    await connection.commit()
 | 
			
		||||
 | 
			
		||||
    return await get_last_ps_node_by_creator_and_ps_id(connection, creator_id, validated_schema.ps_id)
 | 
			
		||||
@@ -4,8 +4,17 @@ from api.endpoints.account import api_router as account_router
 | 
			
		||||
from api.endpoints.keyring import api_router as keyring_router
 | 
			
		||||
from api.endpoints.list_events import api_router as listevents_router
 | 
			
		||||
from api.endpoints.process_schema import api_router as processschema_router
 | 
			
		||||
from api.endpoints.ps_node import api_router as ps_node_router
 | 
			
		||||
 | 
			
		||||
list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router, processschema_router]
 | 
			
		||||
list_of_routes = [
 | 
			
		||||
    auth_router,
 | 
			
		||||
    profile_router,
 | 
			
		||||
    account_router,
 | 
			
		||||
    keyring_router,
 | 
			
		||||
    listevents_router,
 | 
			
		||||
    processschema_router,
 | 
			
		||||
    ps_node_router,
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    "list_of_routes",
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ api_router = APIRouter(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllUserResponse)
 | 
			
		||||
async def get_all_account(
 | 
			
		||||
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"),
 | 
			
		||||
@@ -62,7 +62,7 @@ async def get_all_account(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=User)
 | 
			
		||||
async def get_account(
 | 
			
		||||
async def get_account_endpoint(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
@@ -78,7 +78,7 @@ async def get_account(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=User)
 | 
			
		||||
async def create_account(
 | 
			
		||||
async def create_account_endpoint(
 | 
			
		||||
    user: UserCreate,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
@@ -98,7 +98,7 @@ async def create_account(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.put("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=UserUpdate)
 | 
			
		||||
async def update_account(
 | 
			
		||||
async def update_account_endpoint(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    user_update: UserUpdate,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
@@ -126,7 +126,7 @@ async def update_account(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=User)
 | 
			
		||||
async def delete_account(
 | 
			
		||||
async def delete_account_endpoint(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ def get_config():
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("", response_model=Tokens)
 | 
			
		||||
async def login_for_access_token(
 | 
			
		||||
async def login_for_access_token_endpoint(
 | 
			
		||||
    user: Auth,
 | 
			
		||||
    response: Response,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
@@ -84,7 +84,7 @@ async def login_for_access_token(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("/refresh", response_model=Tokens)
 | 
			
		||||
async def refresh(
 | 
			
		||||
async def refresh_endpoint(
 | 
			
		||||
    request: Request,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    Authorize: AuthJWT = Depends(),
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ api_router = APIRouter(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring)
 | 
			
		||||
async def get_keyring(
 | 
			
		||||
async def get_keyring_endpoint(
 | 
			
		||||
    key_id: str, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user)
 | 
			
		||||
):
 | 
			
		||||
    authorize_user = await db_user_role_validation(connection, current_user)
 | 
			
		||||
@@ -36,7 +36,7 @@ async def get_keyring(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring)
 | 
			
		||||
async def create_keyring(
 | 
			
		||||
async def create_keyring_endpoint(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    key_id: str,
 | 
			
		||||
    key: AccountKeyringUpdate,
 | 
			
		||||
@@ -62,7 +62,7 @@ async def create_keyring(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.put("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring)
 | 
			
		||||
async def update_keyring(
 | 
			
		||||
async def update_keyring_endpoint(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    key_id: str,
 | 
			
		||||
    keyring_update: AccountKeyringUpdate,
 | 
			
		||||
@@ -88,7 +88,7 @@ async def update_keyring(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{user_id}/{key_id}", dependencies=[Depends(bearer_schema)], response_model=AccountKeyring)
 | 
			
		||||
async def delete_keyring(
 | 
			
		||||
async def delete_keyring_endpoint(
 | 
			
		||||
    user_id: int,
 | 
			
		||||
    key_id: str,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ api_router = APIRouter(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllListEventResponse)
 | 
			
		||||
async def get_all_list_events(
 | 
			
		||||
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"),
 | 
			
		||||
@@ -72,7 +72,7 @@ async def get_all_list_events(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
 | 
			
		||||
async def get_list_events(
 | 
			
		||||
async def get_list_events_endpoint(
 | 
			
		||||
    list_events_id: int,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
@@ -93,7 +93,7 @@ async def get_list_events(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
 | 
			
		||||
async def create_list_events(
 | 
			
		||||
async def create_list_events_endpoint(
 | 
			
		||||
    list_events: ListEventUpdate,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
@@ -141,7 +141,7 @@ async def update_list_events(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
 | 
			
		||||
async def delete_list_events(
 | 
			
		||||
async def delete_list_events_endpoint(
 | 
			
		||||
    list_events_id: int,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
 
 | 
			
		||||
@@ -9,19 +9,35 @@ from api.db.logic.account import get_user_by_login
 | 
			
		||||
from api.db.logic.process_schema import (
 | 
			
		||||
    create_process_schema,
 | 
			
		||||
    get_process_schema_by_id,
 | 
			
		||||
    get_process_schema_by_title,
 | 
			
		||||
    get_process_schema_page_DTO,
 | 
			
		||||
    update_process_schema_by_id,
 | 
			
		||||
)
 | 
			
		||||
from api.schemas.base import bearer_schema
 | 
			
		||||
from api.schemas.endpoints.process_schema import AllProcessSchemaResponse, ProcessSchemaFilterDTO, ProcessSchemaUpdate
 | 
			
		||||
from api.schemas.process.process_schema import ProcessSchema
 | 
			
		||||
from api.schemas.process.process_schema import ProcessSchema, ProcessSchemaSettingsNode, ProcessSchemaResponse
 | 
			
		||||
from api.schemas.process.ps_node import Ps_NodeFrontResponseNode
 | 
			
		||||
from api.schemas.process.ps_node import Ps_NodeFrontResponse
 | 
			
		||||
from api.services.auth import get_current_user
 | 
			
		||||
from api.services.user_role_validation import (
 | 
			
		||||
    db_user_role_validation_for_list_events_and_process_schema,
 | 
			
		||||
    db_user_role_validation_for_list_events_and_process_schema_by_list_event_id,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from api.db.logic.ps_node import create_ps_node_schema
 | 
			
		||||
from api.db.logic.process_schema import update_process_schema_settings_by_id
 | 
			
		||||
 | 
			
		||||
from orm.tables.process import NodeType
 | 
			
		||||
 | 
			
		||||
from api.utils.to_camel_dict import to_camel_dict
 | 
			
		||||
 | 
			
		||||
from core import VorkNodeRegistry
 | 
			
		||||
 | 
			
		||||
from model_nodes import ListenNodeData
 | 
			
		||||
 | 
			
		||||
from api.utils.node_counter import increment_node_counter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
api_router = APIRouter(
 | 
			
		||||
    prefix="/process_schema",
 | 
			
		||||
    tags=["process schema"],
 | 
			
		||||
@@ -29,7 +45,7 @@ api_router = APIRouter(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllProcessSchemaResponse)
 | 
			
		||||
async def get_all_process_schema(
 | 
			
		||||
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"),
 | 
			
		||||
@@ -37,12 +53,20 @@ async def get_all_process_schema(
 | 
			
		||||
    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"),
 | 
			
		||||
    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"),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
):
 | 
			
		||||
    if show_deleted:
 | 
			
		||||
        status_to_filter = ["DELETED"]
 | 
			
		||||
    elif status_filter:
 | 
			
		||||
        status_to_filter = status_filter
 | 
			
		||||
    else:
 | 
			
		||||
        status_to_filter = None
 | 
			
		||||
 | 
			
		||||
    filters = {
 | 
			
		||||
        **({"status": status_filter} if status_filter else {}),
 | 
			
		||||
        **({"status": status_to_filter} if status_to_filter else {}),
 | 
			
		||||
        **({"owner_id": owner_id} if owner_id else {}),
 | 
			
		||||
        **({"creator_id": [str(creator_id)]} if creator_id else {}),
 | 
			
		||||
    }
 | 
			
		||||
@@ -68,11 +92,11 @@ async def get_all_process_schema(
 | 
			
		||||
    if process_schema_page is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found")
 | 
			
		||||
 | 
			
		||||
    return process_schema_page
 | 
			
		||||
    return to_camel_dict(process_schema_page.model_dump())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.get("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
 | 
			
		||||
async def get_process_schema(
 | 
			
		||||
async def get_process_schema_endpoint(
 | 
			
		||||
    process_schema_id: int,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
@@ -89,31 +113,75 @@ async def get_process_schema(
 | 
			
		||||
    if process_schema_id is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found")
 | 
			
		||||
 | 
			
		||||
    return process_schema_validation
 | 
			
		||||
    return to_camel_dict(process_schema_validation.model_dump())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
 | 
			
		||||
async def create_processschema(
 | 
			
		||||
    process_schema: ProcessSchemaUpdate,
 | 
			
		||||
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchemaResponse)
 | 
			
		||||
async def create_processschema_endpoint(
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
):
 | 
			
		||||
    user_validation = await get_user_by_login(connection, current_user)
 | 
			
		||||
    process_schema_validation = await get_process_schema_by_title(connection, process_schema.title)
 | 
			
		||||
 | 
			
		||||
    if process_schema_validation is None:
 | 
			
		||||
        await create_process_schema(connection, process_schema, user_validation.id)
 | 
			
		||||
        process_schema_new = await get_process_schema_by_title(connection, process_schema.title)
 | 
			
		||||
        return process_schema_new
 | 
			
		||||
    current_node_counter = increment_node_counter()
 | 
			
		||||
    title = f"Новая схема {current_node_counter}"
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        raise HTTPException(
 | 
			
		||||
            status_code=status.HTTP_400_BAD_REQUEST, detail="An process schema with this information already exists."
 | 
			
		||||
        )
 | 
			
		||||
    description = "Default description"
 | 
			
		||||
 | 
			
		||||
    node_id = await create_process_schema(connection, user_validation.id, title, description)
 | 
			
		||||
 | 
			
		||||
    process_schema_new = await get_process_schema_by_id(connection, node_id)
 | 
			
		||||
 | 
			
		||||
| 
					
	
	
	
	
	
	
	
	 
					
					ivan.dev marked this conversation as resolved
					
				 
				
				
					
						cyrussmeat
						commented  
			
		А почему в такой связке не используется last_insert_id и получение схемы по идентификатору из БД, который PK? А почему в такой связке не  используется last_insert_id и получение схемы по идентификатору из БД, который PK?  
			
			
		
				
					
						ivan.dev
						commented  
			
		Логично, сейчас переделаю. Логично, сейчас переделаю.
 
			
			
		 | 
			||||
    start_node_data = ListenNodeData(ps_id=process_schema_new.id, node_type=NodeType.START.value, is_start="True")
 | 
			
		||||
 | 
			
		||||
    start_node_links = {}
 | 
			
		||||
 | 
			
		||||
    registery = VorkNodeRegistry()
 | 
			
		||||
 | 
			
		||||
    vork_node = registery.get("LISTEN")
 | 
			
		||||
 | 
			
		||||
    node_descriptor = vork_node.form()
 | 
			
		||||
 | 
			
		||||
    start_node = vork_node(data=start_node_data.model_dump(), links=start_node_links)
 | 
			
		||||
 | 
			
		||||
    validated_start_schema = start_node.validate()
 | 
			
		||||
 | 
			
		||||
    print(validated_start_schema)
 | 
			
		||||
 | 
			
		||||
    db_start_schema = await create_ps_node_schema(connection, validated_start_schema, user_validation.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(connection, process_schema_new.id, settings_dict)
 | 
			
		||||
 | 
			
		||||
    process_schema_new = await get_process_schema_by_id(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(),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return to_camel_dict(response_data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.put("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
 | 
			
		||||
async def update_process_schema(
 | 
			
		||||
async def update_process_schema_endpoint(
 | 
			
		||||
    process_schema_id: int,
 | 
			
		||||
    process_schema_update: ProcessSchemaUpdate,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
@@ -140,8 +208,8 @@ async def update_process_schema(
 | 
			
		||||
    return process_schema
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.delete("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
 | 
			
		||||
async def delete_process_schema(
 | 
			
		||||
@api_router.delete("/{process_schema_id}", dependencies=[Depends(bearer_schema)], status_code=status.HTTP_200_OK)
 | 
			
		||||
async def delete_process_schema_endpoint(
 | 
			
		||||
    process_schema_id: int,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
@@ -164,6 +232,6 @@ async def delete_process_schema(
 | 
			
		||||
 | 
			
		||||
    await update_process_schema_by_id(connection, updated_values, process_schema_validation)
 | 
			
		||||
 | 
			
		||||
    process_schema = await get_process_schema_by_id(connection, process_schema_id)
 | 
			
		||||
    await get_process_schema_by_id(connection, process_schema_id)
 | 
			
		||||
 | 
			
		||||
    return process_schema
 | 
			
		||||
    return HTTPException(status_code=status.HTTP_200_OK, detail="Process schema deleted successfully")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								api/api/endpoints/ps_node.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								api/api/endpoints/ps_node.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
from fastapi import APIRouter, Depends, HTTPException, status
 | 
			
		||||
 | 
			
		||||
from sqlalchemy.ext.asyncio import AsyncConnection
 | 
			
		||||
 | 
			
		||||
from api.db.connection.session import get_connection_dep
 | 
			
		||||
from api.db.logic.account import get_user_by_login
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import bearer_schema
 | 
			
		||||
from api.schemas.process.process_schema import ProcessSchemaSettingsNodeLink, ProcessSchemaSettingsNode
 | 
			
		||||
from api.schemas.process.ps_node import Ps_NodeFrontResponseNode, Ps_NodeRequest
 | 
			
		||||
from api.schemas.process.ps_node import Ps_NodeFrontResponse
 | 
			
		||||
from api.services.auth import get_current_user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 core import VorkNodeRegistry, VorkNodeLink
 | 
			
		||||
 | 
			
		||||
from model_nodes import VorkNodeLinkData
 | 
			
		||||
from api.utils.to_camel_dict import to_camel_dict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
api_router = APIRouter(
 | 
			
		||||
    prefix="/ps_node",
 | 
			
		||||
    tags=["ps node"],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=Ps_NodeFrontResponse)
 | 
			
		||||
async def create_ps_node_endpoint(
 | 
			
		||||
    ps_node: Ps_NodeRequest,
 | 
			
		||||
    connection: AsyncConnection = Depends(get_connection_dep),
 | 
			
		||||
    current_user=Depends(get_current_user),
 | 
			
		||||
):
 | 
			
		||||
    user_validation = await get_user_by_login(connection, current_user)
 | 
			
		||||
 | 
			
		||||
    registery = VorkNodeRegistry()
 | 
			
		||||
 | 
			
		||||
    vork_node = registery.get(ps_node.data["node_type"])
 | 
			
		||||
 | 
			
		||||
    if vork_node is None:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Node not found")
 | 
			
		||||
 | 
			
		||||
    node_descriptor = vork_node.form()
 | 
			
		||||
    try:
 | 
			
		||||
        node_instance = vork_node(data=ps_node.data, links=ps_node.links)
 | 
			
		||||
 | 
			
		||||
        node_instance_validated = node_instance.validate()
 | 
			
		||||
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
 | 
			
		||||
 | 
			
		||||
    db_ps_node = await create_ps_node_schema(connection, node_instance_validated, user_validation.id)
 | 
			
		||||
    link_name = await get_last_link_name_by_node_id(connection, db_ps_node.ps_id)
 | 
			
		||||
 | 
			
		||||
    link_data = VorkNodeLinkData(
 | 
			
		||||
        parent_port_number=node_instance_validated.parent_port_number,
 | 
			
		||||
        to_id=db_ps_node.id,
 | 
			
		||||
        from_id=node_instance_validated.parent_id,
 | 
			
		||||
        last_link_name=link_name,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    link = VorkNodeLink(data=link_data.model_dump())
 | 
			
		||||
 | 
			
		||||
    validated_link = link.validate()
 | 
			
		||||
 | 
			
		||||
    db_node_link = await create_node_link_schema(connection, validated_link, user_validation.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(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()}],
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    return ps_node_front_response
 | 
			
		||||
@@ -10,7 +10,7 @@ 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
 | 
			
		||||
    # owner_id: Optional[int] = None
 | 
			
		||||
    settings: Optional[Dict[str, Any]] = None
 | 
			
		||||
    status: Optional[ProcessStatus] = None
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,10 +7,11 @@ from pydantic import Field
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MyModel(Base):
 | 
			
		||||
class NodeLink(Base):
 | 
			
		||||
    id: int
 | 
			
		||||
    link_name: str = Field(..., max_length=20)
 | 
			
		||||
    node_id: int
 | 
			
		||||
    link_point_id: int
 | 
			
		||||
    next_node_id: int
 | 
			
		||||
    settings: Dict[str, Any]
 | 
			
		||||
    creator_id: int
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from typing import Any, Dict
 | 
			
		||||
from typing import Any, Dict, Optional, List
 | 
			
		||||
 | 
			
		||||
from orm.tables.process import ProcessStatus
 | 
			
		||||
from orm.tables.process import ProcessStatus, NodeType
 | 
			
		||||
from pydantic import Field
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
from api.schemas.process.ps_node import Ps_NodeFrontResponse
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProcessSchema(Base):
 | 
			
		||||
@@ -16,3 +17,24 @@ class ProcessSchema(Base):
 | 
			
		||||
    created_at: datetime
 | 
			
		||||
    settings: Dict[str, Any]
 | 
			
		||||
    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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,41 @@
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from typing import Any, Dict
 | 
			
		||||
from typing import Any, Dict, Optional, List
 | 
			
		||||
 | 
			
		||||
from orm.tables.process import NodeStatus, NodeType
 | 
			
		||||
 | 
			
		||||
from api.schemas.base import Base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Ps_NodeRequest(Base):
 | 
			
		||||
    data: Dict[str, Any]
 | 
			
		||||
    links: Dict[str, Any]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Ps_Node(Base):
 | 
			
		||||
    id: int
 | 
			
		||||
    ps_id: int
 | 
			
		||||
    node_type: NodeType
 | 
			
		||||
    settings: dict
 | 
			
		||||
    creator_id: Dict[str, Any]
 | 
			
		||||
    creator_id: int
 | 
			
		||||
    created_at: datetime
 | 
			
		||||
    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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								api/api/utils/node_counter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								api/api/utils/node_counter.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
import json
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import Dict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Путь к файлу счётчика (в корне проекта)
 | 
			
		||||
COUNTER_FILE_PATH = Path(__file__).parent.parent.parent / "node_counter.json"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_node_counter() -> int:
 | 
			
		||||
    """
 | 
			
		||||
    Открывает JSON файл и возвращает значение node_counter.
 | 
			
		||||
    Если файл не существует, создаёт его со значением по умолчанию 0.
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        int: Текущее значение счётчика узлов
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    if not COUNTER_FILE_PATH.exists():
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        with open(COUNTER_FILE_PATH, "r", encoding="utf-8") as f:
 | 
			
		||||
            data = json.load(f)
 | 
			
		||||
            return data.get("node_counter", 0)
 | 
			
		||||
    except (json.JSONDecodeError, IOError):
 | 
			
		||||
        initial_data = {"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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def increment_node_counter() -> int:
 | 
			
		||||
    """
 | 
			
		||||
    Увеличивает значение node_counter на 1, сохраняет в файл и возвращает новое значение.
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
        int: Новое значение счётчика (старое значение + 1)
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    current_value = get_node_counter()
 | 
			
		||||
 | 
			
		||||
    new_value = current_value + 1
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    return new_value
 | 
			
		||||
							
								
								
									
										10
									
								
								api/api/utils/to_camel_dict.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								api/api/utils/to_camel_dict.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
from pydantic.alias_generators import to_camel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def to_camel_dict(obj):
 | 
			
		||||
    if isinstance(obj, dict):
 | 
			
		||||
        return {to_camel(key): to_camel_dict(value) for key, value in obj.items()}
 | 
			
		||||
    elif isinstance(obj, list):
 | 
			
		||||
        return [to_camel_dict(item) for item in obj]
 | 
			
		||||
    else:
 | 
			
		||||
        return obj
 | 
			
		||||
							
								
								
									
										2046
									
								
								api/poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2046
									
								
								api/poetry.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -16,8 +16,9 @@ dependencies = [
 | 
			
		||||
    "cryptography (>=44.0.2,<45.0.0)",
 | 
			
		||||
    "pydantic[email] (>=2.11.3,<3.0.0)",
 | 
			
		||||
    "python-multipart (>=0.0.20,<0.0.21)",
 | 
			
		||||
    "requests (>=2.31.0,<3.0.0)",
 | 
			
		||||
    "fastapi-jwt-auth @ git+https://github.com/vvpreo/fastapi-jwt-auth",
 | 
			
		||||
    "core-library @ git+https://gitea.heado.ru/Vorkout/core.git@0.1.0",
 | 
			
		||||
    "vork-core @ git+http://88.86.199.167:3000/Nox/CORE.git",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user
	
Я поглядел, что реализация в process_schema не задействует данный метод. Он нужен?
Это когда стартовая нода была, удалю.