feat: settings, delete port validation #22

Open
ivan.dev wants to merge 3 commits from VORKOUT-31 into master
30 changed files with 147 additions and 180 deletions
Showing only changes of commit a70973032f - Show all commits

View File

@@ -1,7 +1,6 @@
import math import math
from datetime import datetime, timezone from datetime import datetime, timezone
from enum import Enum from enum import Enum
from typing import Optional
from sqlalchemy import insert, select, func, or_, and_, asc, desc from sqlalchemy import insert, select, func, or_, and_, asc, desc
from sqlalchemy.ext.asyncio import AsyncConnection 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 from api.schemas.endpoints.account import all_user_adapter, AllUser, AllUserResponse, UserCreate, UserFilterDTO
async def get_user_account_page_DTO( async def get_user_account_page_DTO(connection: AsyncConnection, filter_dto: UserFilterDTO) -> AllUserResponse | None:
connection: AsyncConnection, filter_dto: UserFilterDTO
) -> Optional[AllUserResponse]:
""" """
Получает список пользователей с пагинацией, фильтрацией и сортировкой через DTO объект. Получает список пользователей с пагинацией, фильтрацией и сортировкой через 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. Получает юзера по id.
""" """
@@ -133,7 +130,7 @@ async def get_user_by_id(connection: AsyncConnection, user_id: int) -> Optional[
return User.model_validate(user) 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. Получает юзера по login.
""" """
@@ -147,7 +144,7 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional
return User.model_validate(user_data) 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. Вносит изменеия в нужное поле таблицы account_table.
""" """
@@ -156,7 +153,7 @@ async def update_user_by_id(connection: AsyncConnection, update_values, user) ->
await connection.commit() 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. Создает нове поле в таблице account_table.
""" """

View File

@@ -1,5 +1,3 @@
from typing import Optional
from sqlalchemy import select, update from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from enum import Enum from enum import Enum
@@ -15,7 +13,7 @@ from api.utils.key_id_gen import KeyIdGenerator
from datetime import datetime, timezone 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 = ( query = (
select(account_table, account_keyring_table) select(account_table, account_keyring_table)
.join(account_keyring_table, account_table.c.id == account_keyring_table.c.owner_id) .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 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 new_status = KeyStatus.EXPIRED
update_query = ( update_query = (
@@ -71,7 +69,7 @@ async def upgrade_old_refresh_token(connection: AsyncConnection, refresh_token)
async def add_new_refresh_token( async def add_new_refresh_token(
connection: AsyncConnection, new_refresh_token, new_refresh_token_expires_time, user connection: AsyncConnection, new_refresh_token, new_refresh_token_expires_time, user
) -> Optional[User]: ) -> User | None:
new_refresh_token = account_keyring_table.insert().values( new_refresh_token = account_keyring_table.insert().values(
owner_id=user.id, owner_id=user.id,
key_type=KeyType.REFRESH_TOKEN, key_type=KeyType.REFRESH_TOKEN,

View File

@@ -1,6 +1,5 @@
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from enum import Enum from enum import Enum
from typing import Optional
from sqlalchemy import insert, select, update from sqlalchemy import insert, select, update
from sqlalchemy.dialects.mysql import insert as mysql_insert 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 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. Получает 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) 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. Вносит изменеия в нужное поле таблицы account_keyring_table.
""" """
@@ -37,7 +36,7 @@ async def update_key_by_id(connection: AsyncConnection, update_values, key) -> O
await connection.commit() 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). Создает нове поле в таблице account_keyring_table).
""" """

View File

@@ -1,4 +1,3 @@
from typing import Optional
import math import math
from datetime import datetime, timezone 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( async def get_list_events_page_DTO(
connection: AsyncConnection, filter_dto: ListEventFilterDTO connection: AsyncConnection, filter_dto: ListEventFilterDTO
) -> Optional[AllListEventResponse]: ) -> AllListEventResponse | None:
""" """
Получает список событий с фильтрацией через DTO объект. Получает список событий с фильтрацией через 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. Получает 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) 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. Получает listevent по id.
""" """
@@ -162,9 +161,7 @@ async def update_list_events_by_id(connection: AsyncConnection, update_values, l
await connection.commit() await connection.commit()
async def create_list_events( async def create_list_events(connection: AsyncConnection, list_events: ListEvent, creator_id: int) -> ListEvent | None:
connection: AsyncConnection, list_events: ListEvent, creator_id: int
) -> Optional[ListEvent]:
""" """
Создает нове поле в таблице list_events_table. Создает нове поле в таблице list_events_table.
""" """

View File

@@ -1,5 +1,3 @@
from typing import Optional, List
from datetime import datetime, timezone from datetime import datetime, timezone
from sqlalchemy import insert, select, desc 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 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. Получает link_name из последней записи node_link по ps_id.
Находит все node_id в ps_node по ps_id, затем ищет связи в node_link Находит все 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( async def get_last_node_link_by_creator_and_ps_id(
connection: AsyncConnection, creator_id: int, node_link_id: int connection: AsyncConnection, creator_id: int, node_link_id: int
) -> Optional[NodeLink]: ) -> NodeLink | None:
""" """
Получает последнюю созданную node_link для данного создателя и процесса. Получает последнюю созданную node_link для данного создателя и процесса.
""" """
@@ -59,7 +57,7 @@ async def create_node_link_schema(
connection: AsyncConnection, connection: AsyncConnection,
validated_link_schema, validated_link_schema,
creator_id: int, creator_id: int,
) -> Optional[NodeLink]: ) -> NodeLink | None:
""" """
Создает нове поле в таблице process_schema_table. Создает нове поле в таблице 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) 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 одним запросом. Получает все активные node_link для списка next_node_id одним запросом.
""" """

View File

@@ -1,4 +1,4 @@
from typing import Optional, Dict, Any from typing import Any
import math import math
from datetime import datetime, timezone from datetime import datetime, timezone
@@ -19,7 +19,7 @@ from api.schemas.endpoints.process_schema import (
async def get_process_schema_page_DTO( async def get_process_schema_page_DTO(
connection: AsyncConnection, filter_dto: ProcessSchemaFilterDTO connection: AsyncConnection, filter_dto: ProcessSchemaFilterDTO
) -> Optional[AllProcessSchemaResponse]: ) -> AllProcessSchemaResponse | None:
""" """
Получает список схем процессов с комплексной фильтрацией через DTO объект. Получает список схем процессов с комплексной фильтрацией через 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. Получает process_schema по id.
""" """
@@ -143,7 +143,7 @@ async def update_process_schema_by_id(connection: AsyncConnection, update_values
async def create_process_schema( async def create_process_schema(
connection: AsyncConnection, creator_id: int, title: str, description: str connection: AsyncConnection, creator_id: int, title: str, description: str
) -> Optional[int]: ) -> int | None:
""" """
Создает новое поле в таблице process_schema_table. Создает новое поле в таблице process_schema_table.
""" """

View File

@@ -1,4 +1,4 @@
from typing import Optional, List, Dict, Any from typing import Any
from datetime import datetime, timezone from datetime import datetime, timezone
@@ -11,7 +11,7 @@ from api.schemas.process.ps_node import Ps_Node
from orm.tables.process import NodeStatus 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. Получает 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( async def get_last_ps_node_by_creator_and_ps_id(
connection: AsyncConnection, creator_id: int, ps_id: int connection: AsyncConnection, creator_id: int, ps_id: int
) -> Optional[Ps_Node]: ) -> Ps_Node | None:
""" """
Получает последнюю созданную ps_node для данного создателя и процесса. Получает последнюю созданную 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) 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. Получает все активные ps_node для данной process_schema.
""" """
@@ -67,8 +67,8 @@ async def create_ps_node_schema(
validated_schema, validated_schema,
node_descriptor, node_descriptor,
creator_id: int, creator_id: int,
settings_payload: Optional[Dict[str, Any]] = None, settings_payload: dict[str, Any] | None = None,
) -> Optional[Ps_Node]: ) -> Ps_Node | None:
""" """
Создает нове поле в таблице process_schema_table. Создает нове поле в таблице 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 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 в правильном порядке: Рекурсивно находит ВСЕ дочерние узлы и возвращает их ID в правильном порядке:
от самых глубоких к корневым. от самых глубоких к корневым.
@@ -144,7 +144,7 @@ async def get_nodes_for_deletion_ordered(connection: AsyncConnection, node_id: i
return ordered_node_ids 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. Очищает settings и удаляет ноды для каждого ps_id.
Возвращает список успешно удаленных ID нод. Возвращает список успешно удаленных ID нод.
@@ -177,7 +177,7 @@ async def delete_ps_nodes_delete_handler(connection: AsyncConnection, node_ids:
return deleted_all 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. Удаляет ноды из поля settings в таблице process_schema по списку node_ids.
""" """

View File

@@ -1,5 +1,3 @@
from typing import List, Optional
from fastapi import APIRouter, Depends, Query, status from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
@@ -23,12 +21,12 @@ api_router = APIRouter(
async def get_all_account_endpoint( async def get_all_account_endpoint(
page: int = Query(1, description="Page number", gt=0), page: int = Query(1, description="Page number", gt=0),
limit: int = Query(10, description="КNumber of items per page", 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"), search: str | None = Query(None, description="Search term to filter by name or login or email"),
status_filter: Optional[List[str]] = Query(None, description="Filter by status"), status_filter: list[str] | None = Query(None, description="Filter by status"),
role_filter: Optional[List[str]] = Query(None, description="Filter by role"), role_filter: list[str] | None = Query(None, description="Filter by role"),
creator_id: Optional[int] = Query(None, description="Filter by creator id"), creator_id: int | None = Query(None, description="Filter by creator id"),
order_field: Optional[str] = Query("id", description="Field to sort by"), order_field: str | None = Query("id", description="Field to sort by"),
order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), order_direction: str | None = Query("asc", description="Sort direction (asc/desc)"),
connection: AsyncConnection = Depends(get_connection_dep), connection: AsyncConnection = Depends(get_connection_dep),
current_user=Depends(get_current_user), current_user=Depends(get_current_user),
): ):

View File

@@ -1,5 +1,3 @@
from typing import List, Optional
from fastapi import APIRouter, Depends, Query, status from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
@@ -23,12 +21,12 @@ api_router = APIRouter(
async def get_all_list_events_endpoint( async def get_all_list_events_endpoint(
page: int = Query(1, description="Page number", gt=0), page: int = Query(1, description="Page number", gt=0),
limit: int = Query(10, description="Number of items per page", 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"), search: str | None = Query(None, description="Search term to filter by title or name"),
order_field: Optional[str] = Query("id", description="Field to sort by"), order_field: str | None = Query("id", description="Field to sort by"),
order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), order_direction: str | None = Query("asc", description="Sort direction (asc/desc)"),
status_filter: Optional[List[str]] = Query(None, description="Filter by status"), status_filter: list[str] | None = Query(None, description="Filter by status"),
state_filter: Optional[List[str]] = Query(None, description="Filter by state"), state_filter: list[str] | None = Query(None, description="Filter by state"),
creator_id: Optional[int] = Query(None, description="Filter by creator id"), creator_id: int | None = Query(None, description="Filter by creator id"),
connection: AsyncConnection = Depends(get_connection_dep), connection: AsyncConnection = Depends(get_connection_dep),
current_user=Depends(get_current_user), current_user=Depends(get_current_user),
): ):

View File

@@ -1,5 +1,3 @@
from typing import List, Optional
from fastapi import APIRouter, Depends, Query, status, HTTPException from fastapi import APIRouter, Depends, Query, status, HTTPException
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
@@ -25,14 +23,14 @@ api_router = APIRouter(
async def get_all_process_schema_endpoint( async def get_all_process_schema_endpoint(
page: int = Query(1, description="Page number", gt=0), page: int = Query(1, description="Page number", gt=0),
limit: int = Query(10, description="Number of items per page", 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"), search: str | None = Query(None, description="Search term to filter by title or description"),
order_field: Optional[str] = Query("id", description="Field to sort by"), order_field: str | None = Query("id", description="Field to sort by"),
order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), order_direction: str | None = Query("asc", description="Sort direction (asc/desc)"),
status_filter: Optional[List[str]] = Query(None, description="Filter by status"), status_filter: list[str] | None = Query(None, description="Filter by status"),
owner_id: Optional[List[str]] = Query(None, description="Filter by owner id"), owner_id: list[str] | None = Query(None, description="Filter by owner id"),
show_deleted: bool = Query(False, description="Show only deleted schemas"), show_deleted: bool = Query(False, description="Show only deleted schemas"),
connection: AsyncConnection = Depends(get_connection_dep), 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), current_user=Depends(get_current_user),
): ):
if show_deleted: if show_deleted:

View File

@@ -2,14 +2,14 @@
Обработчики ошибок для API. Обработчики ошибок для API.
""" """
from typing import Optional, Dict, Any from typing import Any
from fastapi import HTTPException from fastapi import HTTPException
from .error_model.error_types import ServerError, AccessError, OperationError, ValidationError, ErrorType from .error_model.error_types import ServerError, AccessError, OperationError, ValidationError, ErrorType
def handle_api_error( 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:
""" """
Функция для создания HTTPException с правильной структурой ошибки. Функция для создания HTTPException с правильной структурой ошибки.
@@ -30,25 +30,21 @@ def handle_api_error(
return HTTPException(status_code=status_code, detail=error.model_dump(mode="json")) return HTTPException(status_code=status_code, detail=error.model_dump(mode="json"))
def create_server_error( def create_server_error(message: str, status_code: int = 500, details: dict[str, Any] | None = None) -> HTTPException:
message: str, status_code: int = 500, details: Optional[Dict[str, Any]] = None
) -> HTTPException:
return handle_api_error(error_type=ErrorType.SERVER, message=message, status_code=status_code, details=details) return handle_api_error(error_type=ErrorType.SERVER, message=message, status_code=status_code, details=details)
def create_access_error( def create_access_error(message: str, status_code: int = 403, details: dict[str, Any] | None = None) -> HTTPException:
message: str, status_code: int = 403, details: Optional[Dict[str, Any]] = None
) -> HTTPException:
return handle_api_error(error_type=ErrorType.ACCESS, message=message, status_code=status_code, details=details) return handle_api_error(error_type=ErrorType.ACCESS, message=message, status_code=status_code, details=details)
def create_operation_error( 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: ) -> HTTPException:
return handle_api_error(error_type=ErrorType.OPERATION, message=message, status_code=status_code, details=details) return handle_api_error(error_type=ErrorType.OPERATION, message=message, status_code=status_code, details=details)
def create_validation_error( 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: ) -> HTTPException:
return handle_api_error(error_type=ErrorType.VALIDATION, message=message, status_code=status_code, details=details) return handle_api_error(error_type=ErrorType.VALIDATION, message=message, status_code=status_code, details=details)

View File

@@ -3,7 +3,7 @@
""" """
from enum import Enum from enum import Enum
from typing import Optional, Dict, Any from typing import Any
from pydantic import BaseModel from pydantic import BaseModel
@@ -25,7 +25,7 @@ class BaseError(BaseModel):
error_type: ErrorType error_type: ErrorType
message: str message: str
details: Optional[Dict[str, Any]] = None details: dict[str, Any] | None = None
class ServerError(BaseError): class ServerError(BaseError):
@@ -58,4 +58,4 @@ class ValidationError(BaseError):
""" """
error_type: ErrorType = ErrorType.VALIDATION error_type: ErrorType = ErrorType.VALIDATION
field_errors: Optional[Dict[str, str]] = None field_errors: dict[str, str] | None = None

View File

@@ -1,5 +1,4 @@
from datetime import datetime from datetime import datetime
from typing import Optional
from orm.tables.account import AccountRole, AccountStatus from orm.tables.account import AccountRole, AccountStatus
from pydantic import EmailStr, Field from pydantic import EmailStr, Field
@@ -8,13 +7,13 @@ from api.schemas.base import Base
class User(Base): class User(Base):
id: Optional[int] = None id: int | None = None
name: str = Field(..., max_length=100) name: str = Field(..., max_length=100)
login: str = Field(..., max_length=100) login: str = Field(..., max_length=100)
email: Optional[EmailStr] = Field(None, max_length=100) # Электронная почта (может быть None) email: EmailStr | None = Field(None, max_length=100) # Электронная почта (может быть None)
bind_tenant_id: Optional[str] = Field(None, max_length=40) bind_tenant_id: str | None = Field(None, max_length=40)
role: AccountRole role: AccountRole
meta: dict meta: dict
creator_id: Optional[int] = None creator_id: int | None = None
created_at: datetime created_at: datetime
status: AccountStatus status: AccountStatus

View File

@@ -1,5 +1,4 @@
from datetime import datetime from datetime import datetime
from typing import Optional
from orm.tables.account import KeyStatus, KeyType from orm.tables.account import KeyStatus, KeyType
from pydantic import Field from pydantic import Field
@@ -10,8 +9,8 @@ from api.schemas.base import Base
class AccountKeyring(Base): class AccountKeyring(Base):
owner_id: int owner_id: int
key_type: KeyType 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) key_value: str = Field(..., max_length=255)
created_at: datetime created_at: datetime
expiry: Optional[datetime] = None expiry: datetime | None = None
status: KeyStatus status: KeyStatus

View File

@@ -1,5 +1,4 @@
from datetime import datetime from datetime import datetime
from typing import Dict, List, Optional
from orm.tables.account import AccountRole, AccountStatus from orm.tables.account import AccountRole, AccountStatus
from pydantic import EmailStr, Field, TypeAdapter from pydantic import EmailStr, Field, TypeAdapter
@@ -8,24 +7,24 @@ from api.schemas.base import Base
class UserUpdate(Base): class UserUpdate(Base):
name: Optional[str] = Field(None, max_length=100) name: str | None = Field(None, max_length=100)
login: Optional[str] = Field(None, max_length=100) login: str | None = Field(None, max_length=100)
email: Optional[EmailStr] = None email: EmailStr | None = None
password: Optional[str] = None password: str | None = None
bind_tenant_id: Optional[str] = Field(None, max_length=40) bind_tenant_id: str | None = Field(None, max_length=40)
role: Optional[AccountRole] = None role: AccountRole | None = None
meta: Optional[dict] = None meta: dict | None = None
status: Optional[AccountStatus] = None status: AccountStatus | None = None
class UserCreate(Base): class UserCreate(Base):
name: str = Field(max_length=100) name: str = Field(max_length=100)
login: str = Field(max_length=100) login: str = Field(max_length=100)
email: Optional[EmailStr] = None email: EmailStr | None = None
password: Optional[str] = None password: str | None = None
bind_tenant_id: Optional[str] = Field(None, max_length=40) bind_tenant_id: str | None = Field(None, max_length=40)
role: AccountRole role: AccountRole
meta: Optional[dict] = None meta: dict | None = None
status: AccountStatus status: AccountStatus
@@ -33,28 +32,28 @@ class AllUser(Base):
id: int id: int
name: str name: str
login: str login: str
email: Optional[EmailStr] = None email: EmailStr | None = None
bind_tenant_id: Optional[str] = None bind_tenant_id: str | None = None
role: AccountRole role: AccountRole
meta: Optional[dict] = None meta: dict | None = None
creator_id: Optional[int] = None creator_id: int | None = None
created_at: datetime created_at: datetime
status: AccountStatus status: AccountStatus
class AllUserResponse(Base): class AllUserResponse(Base):
users: List[AllUser] users: list[AllUser]
amount_count: int amount_count: int
amount_pages: int amount_pages: int
current_page: int current_page: int
limit: int limit: int
all_user_adapter = TypeAdapter(List[AllUser]) all_user_adapter = TypeAdapter(list[AllUser])
class UserFilterDTO(Base): class UserFilterDTO(Base):
pagination: Dict[str, int] pagination: dict[str, int]
search: Optional[str] = None search: str | None = None
order: Optional[Dict[str, str]] = None order: dict[str, str] | None = None
filters: Optional[Dict[str, List[str]]] = None filters: dict[str, list[str]] | None = None

View File

@@ -1,5 +1,3 @@
from typing import Optional
from orm.tables.account import KeyStatus, KeyType from orm.tables.account import KeyStatus, KeyType
from pydantic import Field from pydantic import Field
@@ -7,7 +5,7 @@ from api.schemas.base import Base
class AccountKeyringUpdate(Base): class AccountKeyringUpdate(Base):
owner_id: Optional[int] = None owner_id: int | None = None
key_type: Optional[KeyType] = None key_type: KeyType | None = None
key_value: Optional[str] = Field(None, max_length=255) key_value: str | None = Field(None, max_length=255)
status: Optional[KeyStatus] = None status: KeyStatus | None = None

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List, Optional from typing import Any
from orm.tables.events import EventState, EventStatus from orm.tables.events import EventState, EventStatus
from pydantic import Field, TypeAdapter from pydantic import Field, TypeAdapter
@@ -8,11 +8,11 @@ from api.schemas.base import Base
class ListEventUpdate(Base): class ListEventUpdate(Base):
name: Optional[str] = Field(None, max_length=40) name: str | None = Field(None, max_length=40)
title: Optional[str] = Field(None, max_length=64) title: str | None = Field(None, max_length=64)
schema_: Optional[Dict[str, Any]] = Field(None, alias="schema") schema_: dict[str, Any] | None = Field(None, alias="schema")
state: Optional[EventState] = None state: EventState | None = None
status: Optional[EventStatus] = None status: EventStatus | None = None
class AllListEvent(Base): class AllListEvent(Base):
@@ -21,24 +21,24 @@ class AllListEvent(Base):
title: str title: str
creator_id: int creator_id: int
created_at: datetime created_at: datetime
schema_: Dict[str, Any] = Field(default={}, alias="schema") schema_: dict[str, Any] = Field(default={}, alias="schema")
state: EventState state: EventState
status: EventStatus status: EventStatus
class AllListEventResponse(Base): class AllListEventResponse(Base):
list_event: List[AllListEvent] list_event: list[AllListEvent]
amount_count: int amount_count: int
amount_pages: int amount_pages: int
current_page: int current_page: int
limit: int limit: int
all_list_event_adapter = TypeAdapter(List[AllListEvent]) all_list_event_adapter = TypeAdapter(list[AllListEvent])
class ListEventFilterDTO(Base): class ListEventFilterDTO(Base):
pagination: Dict[str, int] pagination: dict[str, int]
search: Optional[str] = None search: str | None = None
order: Optional[Dict[str, str]] = None order: dict[str, str] | None = None
filters: Optional[Dict[str, List[str]]] = None filters: dict[str, list[str]] | None = None

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List, Optional from typing import Any
from orm.tables.process import ProcessStatus from orm.tables.process import ProcessStatus
from pydantic import Field, TypeAdapter from pydantic import Field, TypeAdapter
@@ -8,11 +8,11 @@ from api.schemas.base import Base
class ProcessSchemaUpdate(Base): class ProcessSchemaUpdate(Base):
title: Optional[str] = Field(None, max_length=100) title: str | None = Field(None, max_length=100)
description: Optional[str] = None description: str | None = None
# owner_id: Optional[int] = None # owner_id: int | None = None
settings: Optional[Dict[str, Any]] = None settings: dict[str, Any] | None = None
status: Optional[ProcessStatus] = None status: ProcessStatus | None = None
class AllProcessSchema(Base): class AllProcessSchema(Base):
@@ -22,23 +22,23 @@ class AllProcessSchema(Base):
owner_id: int owner_id: int
creator_id: int creator_id: int
created_at: datetime created_at: datetime
settings: Dict[str, Any] settings: dict[str, Any]
status: ProcessStatus status: ProcessStatus
class AllProcessSchemaResponse(Base): class AllProcessSchemaResponse(Base):
process_schema: List[AllProcessSchema] process_schema: list[AllProcessSchema]
amount_count: int amount_count: int
amount_pages: int amount_pages: int
current_page: int current_page: int
limit: int limit: int
all_process_schema_adapter = TypeAdapter(List[AllProcessSchema]) all_process_schema_adapter = TypeAdapter(list[AllProcessSchema])
class ProcessSchemaFilterDTO(Base): class ProcessSchemaFilterDTO(Base):
pagination: Dict[str, int] pagination: dict[str, int]
search: Optional[str] = None search: str | None = None
order: Optional[Dict[str, str]] = None order: dict[str, str] | None = None
filters: Optional[Dict[str, List[str]]] = None filters: dict[str, list[str]] | None = None

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict from typing import Any
from orm.tables.events import EventState, EventStatus from orm.tables.events import EventState, EventStatus
from pydantic import Field from pydantic import Field
@@ -13,6 +13,6 @@ class ListEvent(Base):
title: str = Field(..., max_length=64) title: str = Field(..., max_length=64)
creator_id: int creator_id: int
created_at: datetime created_at: datetime
schema_: Dict[str, Any] = Field(..., alias="schema") schema_: dict[str, Any] = Field(..., alias="schema")
state: EventState state: EventState
status: EventStatus status: EventStatus

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict from typing import Any
from orm.tables.process import NodeStatus from orm.tables.process import NodeStatus
from pydantic import Field from pydantic import Field
@@ -13,7 +13,7 @@ class NodeLink(Base):
node_id: int node_id: int
link_point_id: int link_point_id: int
next_node_id: int next_node_id: int
settings: Dict[str, Any] settings: dict[str, Any]
creator_id: int creator_id: int
created_at: datetime created_at: datetime
status: NodeStatus status: NodeStatus

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List from typing import Any
from orm.tables.process import ProcessStatus from orm.tables.process import ProcessStatus
from pydantic import Field from pydantic import Field
@@ -15,10 +15,10 @@ class ProcessSchema(Base):
owner_id: int owner_id: int
creator_id: int creator_id: int
created_at: datetime created_at: datetime
settings: Dict[str, Any] settings: dict[str, Any]
status: ProcessStatus status: ProcessStatus
class ProcessSchemaResponse(Base): class ProcessSchemaResponse(Base):
process_schema: ProcessSchema process_schema: ProcessSchema
nodes: List[Ps_NodeFrontResponse] nodes: list[Ps_NodeFrontResponse]
ivan.dev marked this conversation as resolved Outdated

Вроде же на не старом питоне сидим, зачем тут deprecated тайпинги? Хотя, судя по всему, это не в одном месте проекта имеется.

Вроде же на не старом питоне сидим, зачем тут deprecated тайпинги? Хотя, судя по всему, это не в одном месте проекта имеется.

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict, Optional, List from typing import Any
from orm.tables.process import NodeStatus, NodeType from orm.tables.process import NodeStatus, NodeType
@@ -14,8 +14,8 @@ class Ps_NodeDeleteRequest(Base):
class Ps_NodeRequest(Base): class Ps_NodeRequest(Base):
data: Dict[str, Any] data: dict[str, Any]
links: Dict[str, Any] links: dict[str, Any]
class Ps_Node(Base): class Ps_Node(Base):
@@ -29,5 +29,5 @@ class Ps_Node(Base):
class Ps_NodeFrontResponse(Base): class Ps_NodeFrontResponse(Base):
node: Optional[Dict[str, Any]] = None node: dict[str, Any] | None = None
link: Optional[List[Dict[str, Any]]] = None link: list[dict[str, Any]] | None = None

View File

@@ -1,5 +1,3 @@
from typing import Optional
from fastapi import HTTPException, Request from fastapi import HTTPException, Request
from orm.tables.account import AccountStatus from orm.tables.account import AccountStatus
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
@@ -15,7 +13,7 @@ async def get_current_user(request: Request) -> str | HTTPException:
return request.state.current_user 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) sql_user, sql_password = await get_user(connection, username)
if not sql_user or sql_user.status != AccountStatus.ACTIVE: if not sql_user or sql_user.status != AccountStatus.ACTIVE:

View File

@@ -1,4 +1,3 @@
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from orm.tables.account import AccountStatus from orm.tables.account import AccountStatus
@@ -19,13 +18,13 @@ class AccountService:
def __init__(self, connection: AsyncConnection): def __init__(self, connection: AsyncConnection):
self.connection = connection 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) 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. Получает пользователя по ID.
""" """

View File

@@ -1,4 +1,3 @@
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from orm.tables.account import KeyStatus from orm.tables.account import KeyStatus
@@ -15,7 +14,7 @@ class KeyringService:
def __init__(self, connection: AsyncConnection): def __init__(self, connection: AsyncConnection):
self.connection = connection self.connection = connection
async def get(self, key_id: str) -> Optional[AccountKeyring]: async def get(self, key_id: str) -> AccountKeyring | None:
""" """
Получает keyring по key_id. Получает keyring по key_id.
""" """

View File

@@ -1,4 +1,3 @@
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from orm.tables.events import EventStatus from orm.tables.events import EventStatus
@@ -19,25 +18,25 @@ class ListEventsService:
def __init__(self, connection: AsyncConnection): def __init__(self, connection: AsyncConnection):
self.connection = connection 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) 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. Получает событие по ID.
""" """
return await get_list_events_by_id(self.connection, list_events_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. Получает событие по name.
""" """
return await get_list_events_by_name(self.connection, 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:
""" """
Создаёт новое событие. Создаёт новое событие.
""" """

View File

@@ -1,4 +1,4 @@
from typing import Optional, Dict, Any from typing import Any
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from orm.tables.process import ProcessStatus from orm.tables.process import ProcessStatus
@@ -25,13 +25,13 @@ class ProcessSchemaService:
def __init__(self, connection: AsyncConnection): def __init__(self, connection: AsyncConnection):
self.connection = connection 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) 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 со всеми нодами и линками. Получает схему процесса по ID со всеми нодами и линками.
""" """
@@ -66,7 +66,7 @@ class ProcessSchemaService:
nodes=nodes_response, nodes=nodes_response,
) )
async def create(self, creator_id: int) -> Dict[str, Any]: async def create(self, creator_id: int) -> dict[str, Any]:
""" """
Создаёт новую схему процесса с начальной нодой LISTEN. Создаёт новую схему процесса с начальной нодой LISTEN.
""" """

View File

@@ -1,4 +1,3 @@
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from api.db.logic.account import get_user_by_id, get_user_by_login, update_user_by_id 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): def __init__(self, connection: AsyncConnection):
self.connection = connection self.connection = connection
async def get_by_login(self, login: str) -> Optional[User]: async def get_by_login(self, login: str) -> User | None:
""" """
Получает пользователя по логину. Получает пользователя по логину.
""" """

View File

@@ -1,4 +1,4 @@
from typing import List, Dict, Any from typing import Any
from sqlalchemy.ext.asyncio import AsyncConnection from sqlalchemy.ext.asyncio import AsyncConnection
from api.db.logic.ps_node import ( from api.db.logic.ps_node import (
@@ -18,7 +18,7 @@ class PsNodeService:
def __init__(self, connection: AsyncConnection): def __init__(self, connection: AsyncConnection):
self.connection = connection 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( 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: ) -> Ps_NodeFrontResponse:
""" """
Создаёт новую ноду с линком и обновляет настройки схемы процесса. Создаёт новую ноду с линком и обновляет настройки схемы процесса.

View File

@@ -1,6 +1,5 @@
import json import json
from pathlib import Path from pathlib import Path
from typing import Dict
# Путь к файлу счётчика (в корне проекта) # Путь к файлу счётчика (в корне проекта)
@@ -17,7 +16,7 @@ def get_node_counter() -> int:
""" """
if not COUNTER_FILE_PATH.exists(): 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: with open(COUNTER_FILE_PATH, "w", encoding="utf-8") as f:
json.dump(initial_data, f, indent=2, ensure_ascii=False) json.dump(initial_data, f, indent=2, ensure_ascii=False)
return 0 return 0
@@ -45,7 +44,7 @@ def increment_node_counter() -> int:
new_value = current_value + 1 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: with open(COUNTER_FILE_PATH, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False) json.dump(data, f, indent=2, ensure_ascii=False)