From f550b86c681e65e740c29dd1fdbce1cca13719ee Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Mon, 30 Jun 2025 15:37:07 +0500 Subject: [PATCH 01/16] feat: CRUD ListEvent --- api/api/db/logic/listevents.py | 173 ++++++++++++++++++++ api/api/db/tables/account.py | 2 - api/api/endpoints/__init__.py | 3 +- api/api/endpoints/listevents.py | 174 +++++++++++++++++++++ api/api/schemas/endpoints/list_events.py | 37 +++++ api/api/schemas/events/list_events.py | 17 +- api/api/services/update_data_validation.py | 35 +++++ api/api/services/user_role_validation.py | 14 ++ 8 files changed, 438 insertions(+), 17 deletions(-) create mode 100644 api/api/db/logic/listevents.py create mode 100644 api/api/endpoints/listevents.py create mode 100644 api/api/schemas/endpoints/list_events.py diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py new file mode 100644 index 0000000..7f1d0e1 --- /dev/null +++ b/api/api/db/logic/listevents.py @@ -0,0 +1,173 @@ +from typing import Optional +import math + +from datetime import datetime, timezone + +from sqlalchemy import insert, select, func +from sqlalchemy.ext.asyncio import AsyncConnection +from enum import Enum + +from api.db.tables.events import list_events_table + + +from api.schemas.events.list_events import ListEvent + + +from api.schemas.endpoints.list_events import all_list_event_adapter,AllListEventResponse + + +async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator_id: int, page: int, limit: int) -> Optional[AllListEventResponse]: + """ + Получает список событий заданного создателя по значениям page и limit и creator_id. + """ + + first_event = page * limit - limit + print(creator_id) + query = ( + select( + list_events_table.c.id, + list_events_table.c.name, + list_events_table.c.title, + list_events_table.c.creator_id, + list_events_table.c.created_at, + list_events_table.c.schema, + list_events_table.c.state, + list_events_table.c.status, + ) + .where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id + .order_by(list_events_table.c.id) + .offset(first_event) + .limit(limit) + ) + + count_query = ( + select(func.count()) + .select_from(list_events_table) + .where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id + ) + + result = await connection.execute(query) + count_result = await connection.execute(count_query) + + events_data = result.mappings().all() + total_count = count_result.scalar() + total_pages = math.ceil(total_count / limit) + + # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные + validated_list_event = all_list_event_adapter.validate_python(events_data) + + return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages) + + +async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[ListEvent]: + """ + Получает список ползовелей заданных значениями page, limit. + """ + + first_event = page * limit - (limit) + + query = ( + select( + list_events_table.c.id, + list_events_table.c.name, + list_events_table.c.title, + list_events_table.c.creator_id, + list_events_table.c.created_at, + list_events_table.c.schema, + list_events_table.c.state, + list_events_table.c.status, + ) + .order_by(list_events_table.c.id) + .offset(first_event) + .limit(limit) + ) + + count_query = select(func.count()).select_from(list_events_table) + + result = await connection.execute(query) + count_result = await connection.execute(count_query) + + events_data = result.mappings().all() + total_count = count_result.scalar() + total_pages = math.ceil(total_count / limit) + + # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные + validated_list_event = all_list_event_adapter.validate_python(events_data) + + return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages) + +async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: + """ + Получает юзера по login. + """ + query = select(list_events_table).where(list_events_table.c.name == name) + + listevents_db_cursor = await connection.execute(query) + listevents_db = listevents_db_cursor.one_or_none() + + if not listevents_db: + return None + + listevents_data = { + column.name: ( + getattr(listevents_db, column.name).name + if isinstance(getattr(listevents_db, column.name), Enum) + else getattr(listevents_db, column.name) + ) + for column in list_events_table.columns + } + + return ListEvent.model_validate(listevents_data) + +async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional[ListEvent]: + """ + Получает listevent по id. + """ + query = select(list_events_table).where(list_events_table.c.id == id) + + listevents_db_cursor = await connection.execute(query) + listevents_db = listevents_db_cursor.one_or_none() + + if not listevents_db: + return None + + listevents_data = { + column.name: ( + getattr(listevents_db, column.name).name + if isinstance(getattr(listevents_db, column.name), Enum) + else getattr(listevents_db, column.name) + ) + for column in list_events_table.columns + } + + return ListEvent.model_validate(listevents_data) + +async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents) -> Optional[ListEvent]: + """ + Вносит изменеия в нужное поле таблицы account_table. + """ + await connection.execute(list_events_table.update().where(list_events_table.c.id == listevents.id).values(**update_values)) + + await connection.commit() + + + +async def create_listevents(connection: AsyncConnection, listevents: ListEvent, creator_id: int) -> Optional[ListEvent]: + """ + Создает нове поле в таблице list_events_table. + """ + query = insert(list_events_table).values( + name=listevents.name, + title=listevents.title, # добавлено поле title + creator_id=creator_id, + created_at=datetime.now(timezone.utc), + schema=listevents.schema, # добавлено поле schema + state=listevents.state.value, # добавлено поле state + status=listevents.status.value # добавлено поле status + ) + + await connection.execute(query) + + await connection.commit() + + return listevents diff --git a/api/api/db/tables/account.py b/api/api/db/tables/account.py index 84c689e..1650378 100644 --- a/api/api/db/tables/account.py +++ b/api/api/db/tables/account.py @@ -3,8 +3,6 @@ import enum from sqlalchemy import Table, Column, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index from sqlalchemy.sql import func -from enum import Enum - from api.db.sql_types import UnsignedInt from api.db import metadata diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index 6e98978..0a51e78 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -2,8 +2,9 @@ from api.endpoints.auth import api_router as auth_router from api.endpoints.profile import api_router as profile_router from api.endpoints.account import api_router as account_router from api.endpoints.keyring import api_router as keyring_router +from api.endpoints.listevents import api_router as listevents_router -list_of_routes = [auth_router, profile_router, account_router, keyring_router] +list_of_routes = [auth_router, profile_router, account_router, keyring_router,listevents_router] __all__ = [ "list_of_routes", diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py new file mode 100644 index 0000000..a9d6fce --- /dev/null +++ b/api/api/endpoints/listevents.py @@ -0,0 +1,174 @@ +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.db.logic.listevents import ( + get_listevents_by_name, + get_listevents_by_id, + create_listevents, + update_listevents_by_id, + get_listevents_page, + get_listevents_page_by_creator_id + +) + + +from api.schemas.events.list_events import ListEvent +from api.db.tables.events import EventStatus + +from api.schemas.base import bearer_schema + +from api.schemas.endpoints.list_events import ListEventUpdate,AllListEventResponse + +from api.services.auth import get_current_user + +from api.services.user_role_validation import db_user_role_validation_for_listevents_by_listevent_id,db_user_role_validation_for_listevents +from api.services.update_data_validation import update_listevents_data_changes + + +api_router = APIRouter( + prefix="/listevents", + tags=["list events"], +) + +@api_router.get("", + dependencies=[Depends(bearer_schema)], + response_model=AllListEventResponse) +async def get_all_list_events( + page: int = 1, + limit: int = 10, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + + authorize_user,page_flag = await db_user_role_validation_for_listevents(connection, current_user) + + if page_flag: + + list_eventslist = await get_listevents_page(connection, page, limit) + print(list_eventslist) + if list_eventslist is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + + return list_eventslist + else: + list_events_list = await get_listevents_page_by_creator_id(connection,authorize_user.id, page, limit) + + if list_events_list is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + + return list_events_list + + + + + + +@api_router.get("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +async def get_list_events( + listevents_id: int, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user) +): + listevents_validation = await get_listevents_by_id(connection, listevents_id) + + if listevents_validation is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + + authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id) + + + if listevents_id is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + + return listevents_validation + + +@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +async def create_list_events( + listevents: ListEventUpdate, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user) +): + + user_validation = await get_user_by_login(connection, current_user) + listevents_validation = await get_listevents_by_name(connection, listevents.name) + + if listevents_validation is None: + await create_listevents(connection, listevents, user_validation.id) + user_new = await get_listevents_by_name(connection, listevents.name) + return user_new + + else: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, detail="An List events with this information already exists." + ) + +@api_router.put("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +async def update_listevents( + listevents_id: int, + listevents_update: ListEventUpdate, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + + listevents_validation = await get_listevents_by_id(connection, listevents_id) + + if listevents_validation is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + + authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id) + + update_values = update_listevents_data_changes(listevents_update, listevents_validation) + + if update_values is None: + return listevents_validation + + listevents_update_data = ListEvent.model_validate({**listevents_validation.model_dump(), **update_values}) + + await update_listevents_by_id(connection, update_values, listevents_validation) + + listevents = await get_listevents_by_id(connection, listevents_id) + + return listevents + + +@api_router.delete("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +async def delete_list_events( + listevents_id: int, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + + listevents_validation = await get_listevents_by_id(connection, listevents_id) + + if listevents_validation is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + + authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id) + + listevents_update = ListEventUpdate(status=EventStatus.DELETED.value) + + + update_values = update_listevents_data_changes(listevents_update, listevents_validation) + + if update_values is None: + return listevents_validation + + await update_listevents_by_id(connection, update_values, listevents_validation) + + listevents = await get_listevents_by_id(connection, listevents_id) + + return listevents diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py new file mode 100644 index 0000000..762c00a --- /dev/null +++ b/api/api/schemas/endpoints/list_events.py @@ -0,0 +1,37 @@ +from pydantic import Field, TypeAdapter +from typing import Optional,Dict, Any, List +from datetime import datetime + + +from api.schemas.base import Base +from api.db.tables.events import EventState,EventStatus + + +class ListEventUpdate(Base): + id: Optional[int] = None + name: Optional[str] = Field(None, max_length=40) + title: Optional[str] = Field(None, max_length=64) + creator_id: Optional[int] = None + created_at: Optional[datetime]= None + schema: Optional[Dict[str, Any]]= None + state: Optional[EventState]= None + status: Optional[EventStatus]= None + +class AllListEvent(Base): + id: int + name: str + title: str + creator_id: int + created_at: datetime + schema: Dict[str, Any] = Field(default={}) + state: EventState + status: EventStatus + + +class AllListEventResponse(Base): + list_event: List[AllListEvent] + amount_count: int + amount_pages: int + + +all_list_event_adapter = TypeAdapter(List[AllListEvent]) diff --git a/api/api/schemas/events/list_events.py b/api/api/schemas/events/list_events.py index 2df94c7..d4d70d2 100644 --- a/api/api/schemas/events/list_events.py +++ b/api/api/schemas/events/list_events.py @@ -1,20 +1,9 @@ from pydantic import Field from typing import Dict, Any from datetime import datetime -from enum import Enum from api.schemas.base import Base - - -class State(Enum): - AUTO = "Auto" - DESCRIPTED = "Descripted" - - -class Status(Enum): - ACTIVE = "Active" - DISABLED = "Disabled" - DELETED = "Deleted" +from api.db.tables.events import EventState,EventStatus class ListEvent(Base): @@ -24,5 +13,5 @@ class ListEvent(Base): creator_id: int created_at: datetime schema: Dict[str, Any] - state: State - status: Status + state: EventState + status: EventStatus diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py index 349a0a9..5c0438e 100644 --- a/api/api/services/update_data_validation.py +++ b/api/api/services/update_data_validation.py @@ -4,6 +4,8 @@ from api.schemas.endpoints.account import UserUpdate from api.db.tables.account import KeyType, KeyStatus from api.schemas.endpoints.account_keyring import AccountKeyringUpdate from api.db.tables.account import AccountRole, AccountStatus +from api.schemas.endpoints.list_events import ListEventUpdate +from api.db.tables.events import EventState, EventStatus def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: @@ -72,3 +74,36 @@ def update_key_data_changes(update_data: AccountKeyringUpdate, key) -> Optional[ changes[field] = new_value return changes if changes else None + +def update_listevents_data_changes(update_data: ListEventUpdate, listevents) -> Optional[dict]: + """ + Сравнивает данные для обновления с текущими значениями listevents. + Возвращает: + - None, если нет изменений + - Словарь {поле: новое_значение} для измененных полей + """ + update_values = {} + changes = {} + + for field, value in update_data.model_dump(exclude_unset=True).items(): + if value is None: + continue + + if isinstance(value, (EventState, EventStatus)): + update_values[field] = value.value + else: + update_values[field] = value + + for field, new_value in update_values.items(): + if not hasattr(listevents, field): + continue + + current_value = getattr(listevents, field) + + if isinstance(current_value, Enum): + current_value = current_value.value + + if current_value != new_value: + changes[field] = new_value + + return changes if changes else None diff --git a/api/api/services/user_role_validation.py b/api/api/services/user_role_validation.py index 93670ef..dce18f5 100644 --- a/api/api/services/user_role_validation.py +++ b/api/api/services/user_role_validation.py @@ -11,3 +11,17 @@ async def db_user_role_validation(connection, current_user): if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") return authorize_user + +async def db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,current_lisevents_creator_id): + authorize_user = await get_user_by_login(connection, current_user) + if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: + if authorize_user.id != current_lisevents_creator_id: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") + return authorize_user + +async def db_user_role_validation_for_listevents(connection, current_user): + authorize_user = await get_user_by_login(connection, current_user) + if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: + return authorize_user,False + else: + return authorize_user,True From 0bff556b10005dddbec629fac22877893556959e Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Tue, 1 Jul 2025 22:31:16 +0500 Subject: [PATCH 02/16] fix: page schems, name --- api/api/db/logic/listevents.py | 10 ++++++---- api/api/endpoints/listevents.py | 4 ++-- api/api/schemas/endpoints/list_events.py | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index 7f1d0e1..b801a56 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -56,10 +56,11 @@ async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные validated_list_event = all_list_event_adapter.validate_python(events_data) - return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages) + return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages, current_page=page, + limit = limit) -async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[ListEvent]: +async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]: """ Получает список ползовелей заданных значениями page, limit. """ @@ -94,7 +95,8 @@ async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optio # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные validated_list_event = all_list_event_adapter.validate_python(events_data) - return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages) + return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages,current_page=page, + limit = limit) async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: """ @@ -142,7 +144,7 @@ async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional return ListEvent.model_validate(listevents_data) -async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents) -> Optional[ListEvent]: +async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents): """ Вносит изменеия в нужное поле таблицы account_table. """ diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py index a9d6fce..c54b6c8 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/listevents.py @@ -108,8 +108,8 @@ async def create_list_events( if listevents_validation is None: await create_listevents(connection, listevents, user_validation.id) - user_new = await get_listevents_by_name(connection, listevents.name) - return user_new + listevents_new = await get_listevents_by_name(connection, listevents.name) + return listevents_new else: raise HTTPException( diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 762c00a..141026e 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -32,6 +32,7 @@ class AllListEventResponse(Base): list_event: List[AllListEvent] amount_count: int amount_pages: int - + current_page: int + limit: int all_list_event_adapter = TypeAdapter(List[AllListEvent]) From 3d5d717962ce3f4fd2d3813cc7cb742eeb555c7e Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Wed, 2 Jul 2025 11:37:10 +0500 Subject: [PATCH 03/16] fix: removed id for update data --- api/api/schemas/endpoints/account.py | 2 +- api/api/schemas/endpoints/list_events.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index 37ceeea..829db8b 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -8,7 +8,7 @@ from api.schemas.base import Base class UserUpdate(Base): - id: Optional[int] = None + # id: Optional[int] = None name: Optional[str] = Field(None, max_length=100) login: Optional[str] = Field(None, max_length=100) email: Optional[EmailStr] = None diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 141026e..2e1c30f 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -8,7 +8,7 @@ from api.db.tables.events import EventState,EventStatus class ListEventUpdate(Base): - id: Optional[int] = None + # id: Optional[int] = None name: Optional[str] = Field(None, max_length=40) title: Optional[str] = Field(None, max_length=64) creator_id: Optional[int] = None From a90a802659486acb5d88664d53c5807f2cc97ff3 Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Wed, 2 Jul 2025 11:43:24 +0500 Subject: [PATCH 04/16] fix: update data --- api/api/schemas/endpoints/account.py | 4 ++-- api/api/schemas/endpoints/account_keyring.py | 6 +++--- api/api/schemas/endpoints/list_events.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index 829db8b..f1b9b10 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -15,8 +15,8 @@ class UserUpdate(Base): bind_tenant_id: Optional[str] = Field(None, max_length=40) role: Optional[AccountRole] = None meta: Optional[dict] = None - creator_id: Optional[int] = None - created_at: Optional[datetime] = None + # creator_id: Optional[int] = None + # created_at: Optional[datetime] = None status: Optional[AccountStatus] = None diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index b5f5193..1d3ed81 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -10,8 +10,8 @@ from api.schemas.base import Base class AccountKeyringUpdate(Base): owner_id: Optional[int] = None key_type: Optional[KeyType] = None - key_id: Optional[str] = Field(None, max_length=40) + # key_id: Optional[str] = Field(None, max_length=40) key_value: Optional[str] = Field(None, max_length=255) - created_at: Optional[datetime] = None - expiry: Optional[datetime] = None + # created_at: Optional[datetime] = None + # expiry: Optional[datetime] = None status: Optional[KeyStatus] = None diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 2e1c30f..0b85199 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -11,8 +11,8 @@ class ListEventUpdate(Base): # id: Optional[int] = None name: Optional[str] = Field(None, max_length=40) title: Optional[str] = Field(None, max_length=64) - creator_id: Optional[int] = None - created_at: Optional[datetime]= None + # creator_id: Optional[int] = None + # created_at: Optional[datetime]= None schema: Optional[Dict[str, Any]]= None state: Optional[EventState]= None status: Optional[EventStatus]= None From f65f4caf5c77240b7da6c2a3b14119247980b2ca Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Wed, 2 Jul 2025 11:48:23 +0500 Subject: [PATCH 05/16] fix: description --- api/api/db/logic/listevents.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index b801a56..bdd03b2 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -22,7 +22,6 @@ async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator """ first_event = page * limit - limit - print(creator_id) query = ( select( list_events_table.c.id, @@ -62,7 +61,7 @@ async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]: """ - Получает список ползовелей заданных значениями page, limit. + Получает список событий заданного создателя по значениям page и limit. """ first_event = page * limit - (limit) @@ -100,7 +99,7 @@ async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optio async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: """ - Получает юзера по login. + Получает list events по name. """ query = select(list_events_table).where(list_events_table.c.name == name) @@ -146,7 +145,7 @@ async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents): """ - Вносит изменеия в нужное поле таблицы account_table. + Вносит изменеия в нужное поле таблицы list_events_table. """ await connection.execute(list_events_table.update().where(list_events_table.c.id == listevents.id).values(**update_values)) From 2493cd0d9fcf02b6a066043d5ac2a44bd6a60135 Mon Sep 17 00:00:00 2001 From: Vladislav Syrochkin Date: Wed, 2 Jul 2025 14:14:03 +0500 Subject: [PATCH 06/16] fix(api): fix shadows an attribute in parent in ListEvents for field schema --- api/api/db/logic/listevents.py | 4 ++-- api/api/schemas/endpoints/list_events.py | 4 ++-- api/api/schemas/events/list_events.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index bdd03b2..3d9c245 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -29,7 +29,7 @@ async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator list_events_table.c.title, list_events_table.c.creator_id, list_events_table.c.created_at, - list_events_table.c.schema, + list_events_table.c.schema_, list_events_table.c.state, list_events_table.c.status, ) @@ -162,7 +162,7 @@ async def create_listevents(connection: AsyncConnection, listevents: ListEvent, title=listevents.title, # добавлено поле title creator_id=creator_id, created_at=datetime.now(timezone.utc), - schema=listevents.schema, # добавлено поле schema + schema=listevents.schema_, # добавлено поле schema state=listevents.state.value, # добавлено поле state status=listevents.status.value # добавлено поле status ) diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 0b85199..e0fd96a 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -13,7 +13,7 @@ class ListEventUpdate(Base): title: Optional[str] = Field(None, max_length=64) # creator_id: Optional[int] = None # created_at: Optional[datetime]= None - schema: Optional[Dict[str, Any]]= None + schema_: Optional[Dict[str, Any]]= Field(None, alias="schema") state: Optional[EventState]= None status: Optional[EventStatus]= None @@ -23,7 +23,7 @@ class AllListEvent(Base): title: str creator_id: int created_at: datetime - schema: Dict[str, Any] = Field(default={}) + schema_: Dict[str, Any] = Field(default={}, alias="schema") state: EventState status: EventStatus diff --git a/api/api/schemas/events/list_events.py b/api/api/schemas/events/list_events.py index d4d70d2..d5d79e4 100644 --- a/api/api/schemas/events/list_events.py +++ b/api/api/schemas/events/list_events.py @@ -12,6 +12,6 @@ class ListEvent(Base): title: str = Field(..., max_length=64) creator_id: int created_at: datetime - schema: Dict[str, Any] + schema_: Dict[str, Any] = Field(..., alias="schema") state: EventState status: EventStatus From 269084395443e05c2736c37f534dacea470db0db Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Fri, 4 Jul 2025 11:30:09 +0500 Subject: [PATCH 07/16] fix(api): schemas, name error --- api/api/schemas/endpoints/account.py | 3 --- api/api/schemas/endpoints/account_keyring.py | 3 --- api/api/schemas/endpoints/list_events.py | 3 --- api/api/services/user_role_validation.py | 4 ++-- 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index f1b9b10..759336f 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -8,15 +8,12 @@ from api.schemas.base import Base class UserUpdate(Base): - # id: Optional[int] = None name: Optional[str] = Field(None, max_length=100) login: Optional[str] = Field(None, max_length=100) email: Optional[EmailStr] = None bind_tenant_id: Optional[str] = Field(None, max_length=40) role: Optional[AccountRole] = None meta: Optional[dict] = None - # creator_id: Optional[int] = None - # created_at: Optional[datetime] = None status: Optional[AccountStatus] = None diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index 1d3ed81..382c9e8 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -10,8 +10,5 @@ from api.schemas.base import Base class AccountKeyringUpdate(Base): owner_id: Optional[int] = None key_type: Optional[KeyType] = None - # key_id: Optional[str] = Field(None, max_length=40) key_value: Optional[str] = Field(None, max_length=255) - # created_at: Optional[datetime] = None - # expiry: Optional[datetime] = None status: Optional[KeyStatus] = None diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index e0fd96a..58d8087 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -8,11 +8,8 @@ from api.db.tables.events import EventState,EventStatus class ListEventUpdate(Base): - # id: Optional[int] = None name: Optional[str] = Field(None, max_length=40) title: Optional[str] = Field(None, max_length=64) - # creator_id: Optional[int] = None - # created_at: Optional[datetime]= None schema_: Optional[Dict[str, Any]]= Field(None, alias="schema") state: Optional[EventState]= None status: Optional[EventStatus]= None diff --git a/api/api/services/user_role_validation.py b/api/api/services/user_role_validation.py index dce18f5..fce09c8 100644 --- a/api/api/services/user_role_validation.py +++ b/api/api/services/user_role_validation.py @@ -12,10 +12,10 @@ async def db_user_role_validation(connection, current_user): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") return authorize_user -async def db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,current_lisevents_creator_id): +async def db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,current_listevents_creator_id): authorize_user = await get_user_by_login(connection, current_user) if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: - if authorize_user.id != current_lisevents_creator_id: + if authorize_user.id != current_listevents_creator_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") return authorize_user From 60160d46bea9349b0bb206c046adf26c129151a7 Mon Sep 17 00:00:00 2001 From: Vladislav Syrochkin Date: Fri, 4 Jul 2025 20:08:50 +0500 Subject: [PATCH 08/16] refactor(api): format with ruff --- api/api/db/logic/listevents.py | 34 +++++++++++---- api/api/endpoints/__init__.py | 2 +- api/api/endpoints/listevents.py | 51 ++++++++++------------ api/api/schemas/endpoints/list_events.py | 12 ++--- api/api/schemas/events/list_events.py | 2 +- api/api/services/update_data_validation.py | 1 + api/api/services/user_role_validation.py | 10 +++-- 7 files changed, 65 insertions(+), 47 deletions(-) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index 3d9c245..f667809 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -13,10 +13,12 @@ from api.db.tables.events import list_events_table from api.schemas.events.list_events import ListEvent -from api.schemas.endpoints.list_events import all_list_event_adapter,AllListEventResponse +from api.schemas.endpoints.list_events import all_list_event_adapter, AllListEventResponse -async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator_id: int, page: int, limit: int) -> Optional[AllListEventResponse]: +async def get_listevents_page_by_creator_id( + connection: AsyncConnection, creator_id: int, page: int, limit: int +) -> Optional[AllListEventResponse]: """ Получает список событий заданного создателя по значениям page и limit и creator_id. """ @@ -55,8 +57,13 @@ async def get_listevents_page_by_creator_id(connection: AsyncConnection, creator # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные validated_list_event = all_list_event_adapter.validate_python(events_data) - return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages, current_page=page, - limit = limit) + return AllListEventResponse( + list_event=validated_list_event, + amount_count=total_count, + amount_pages=total_pages, + current_page=page, + limit=limit, + ) async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]: @@ -94,8 +101,14 @@ async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optio # Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные validated_list_event = all_list_event_adapter.validate_python(events_data) - return AllListEventResponse(list_event=validated_list_event, amount_count=total_count, amount_pages=total_pages,current_page=page, - limit = limit) + return AllListEventResponse( + list_event=validated_list_event, + amount_count=total_count, + amount_pages=total_pages, + current_page=page, + limit=limit, + ) + async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: """ @@ -120,6 +133,7 @@ async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Opti return ListEvent.model_validate(listevents_data) + async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional[ListEvent]: """ Получает listevent по id. @@ -143,16 +157,18 @@ async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional return ListEvent.model_validate(listevents_data) + async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents): """ Вносит изменеия в нужное поле таблицы list_events_table. """ - await connection.execute(list_events_table.update().where(list_events_table.c.id == listevents.id).values(**update_values)) + await connection.execute( + list_events_table.update().where(list_events_table.c.id == listevents.id).values(**update_values) + ) await connection.commit() - async def create_listevents(connection: AsyncConnection, listevents: ListEvent, creator_id: int) -> Optional[ListEvent]: """ Создает нове поле в таблице list_events_table. @@ -164,7 +180,7 @@ async def create_listevents(connection: AsyncConnection, listevents: ListEvent, created_at=datetime.now(timezone.utc), schema=listevents.schema_, # добавлено поле schema state=listevents.state.value, # добавлено поле state - status=listevents.status.value # добавлено поле status + status=listevents.status.value, # добавлено поле status ) await connection.execute(query) diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index 0a51e78..a02a1c5 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -4,7 +4,7 @@ from api.endpoints.account import api_router as account_router from api.endpoints.keyring import api_router as keyring_router from api.endpoints.listevents import api_router as listevents_router -list_of_routes = [auth_router, profile_router, account_router, keyring_router,listevents_router] +list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router] __all__ = [ "list_of_routes", diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py index c54b6c8..0a5a0f7 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/listevents.py @@ -10,9 +10,7 @@ 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.db.logic.account import get_user_by_login from api.db.logic.listevents import ( get_listevents_by_name, @@ -20,8 +18,7 @@ from api.db.logic.listevents import ( create_listevents, update_listevents_by_id, get_listevents_page, - get_listevents_page_by_creator_id - + get_listevents_page_by_creator_id, ) @@ -30,11 +27,14 @@ from api.db.tables.events import EventStatus from api.schemas.base import bearer_schema -from api.schemas.endpoints.list_events import ListEventUpdate,AllListEventResponse +from api.schemas.endpoints.list_events import ListEventUpdate, AllListEventResponse from api.services.auth import get_current_user -from api.services.user_role_validation import db_user_role_validation_for_listevents_by_listevent_id,db_user_role_validation_for_listevents +from api.services.user_role_validation import ( + db_user_role_validation_for_listevents_by_listevent_id, + db_user_role_validation_for_listevents, +) from api.services.update_data_validation import update_listevents_data_changes @@ -43,20 +43,17 @@ api_router = APIRouter( tags=["list events"], ) -@api_router.get("", - dependencies=[Depends(bearer_schema)], - response_model=AllListEventResponse) + +@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllListEventResponse) async def get_all_list_events( page: int = 1, limit: int = 10, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - - authorize_user,page_flag = await db_user_role_validation_for_listevents(connection, current_user) + authorize_user, page_flag = await db_user_role_validation_for_listevents(connection, current_user) if page_flag: - list_eventslist = await get_listevents_page(connection, page, limit) print(list_eventslist) if list_eventslist is None: @@ -64,7 +61,7 @@ async def get_all_list_events( return list_eventslist else: - list_events_list = await get_listevents_page_by_creator_id(connection,authorize_user.id, page, limit) + list_events_list = await get_listevents_page_by_creator_id(connection, authorize_user.id, page, limit) if list_events_list is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") @@ -72,23 +69,20 @@ async def get_all_list_events( return list_events_list - - - - @api_router.get("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) async def get_list_events( listevents_id: int, connection: AsyncConnection = Depends(get_connection_dep), - current_user=Depends(get_current_user) + current_user=Depends(get_current_user), ): listevents_validation = await get_listevents_by_id(connection, listevents_id) if listevents_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id) - + authorize_user = await db_user_role_validation_for_listevents_by_listevent_id( + connection, current_user, listevents_validation.creator_id + ) if listevents_id is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") @@ -100,9 +94,8 @@ async def get_list_events( async def create_list_events( listevents: ListEventUpdate, connection: AsyncConnection = Depends(get_connection_dep), - current_user=Depends(get_current_user) + current_user=Depends(get_current_user), ): - user_validation = await get_user_by_login(connection, current_user) listevents_validation = await get_listevents_by_name(connection, listevents.name) @@ -116,6 +109,7 @@ async def create_list_events( status_code=status.HTTP_400_BAD_REQUEST, detail="An List events with this information already exists." ) + @api_router.put("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) async def update_listevents( listevents_id: int, @@ -123,13 +117,14 @@ async def update_listevents( connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - listevents_validation = await get_listevents_by_id(connection, listevents_id) if listevents_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id) + authorize_user = await db_user_role_validation_for_listevents_by_listevent_id( + connection, current_user, listevents_validation.creator_id + ) update_values = update_listevents_data_changes(listevents_update, listevents_validation) @@ -151,17 +146,17 @@ async def delete_list_events( connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - listevents_validation = await get_listevents_by_id(connection, listevents_id) if listevents_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,listevents_validation.creator_id) + authorize_user = await db_user_role_validation_for_listevents_by_listevent_id( + connection, current_user, listevents_validation.creator_id + ) listevents_update = ListEventUpdate(status=EventStatus.DELETED.value) - update_values = update_listevents_data_changes(listevents_update, listevents_validation) if update_values is None: diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 58d8087..c0f99bf 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -1,18 +1,19 @@ from pydantic import Field, TypeAdapter -from typing import Optional,Dict, Any, List +from typing import Optional, Dict, Any, List from datetime import datetime from api.schemas.base import Base -from api.db.tables.events import EventState,EventStatus +from api.db.tables.events import EventState, EventStatus class ListEventUpdate(Base): name: Optional[str] = Field(None, max_length=40) title: Optional[str] = Field(None, max_length=64) - schema_: Optional[Dict[str, Any]]= Field(None, alias="schema") - state: Optional[EventState]= None - status: Optional[EventStatus]= None + schema_: Optional[Dict[str, Any]] = Field(None, alias="schema") + state: Optional[EventState] = None + status: Optional[EventStatus] = None + class AllListEvent(Base): id: int @@ -32,4 +33,5 @@ class AllListEventResponse(Base): current_page: int limit: int + all_list_event_adapter = TypeAdapter(List[AllListEvent]) diff --git a/api/api/schemas/events/list_events.py b/api/api/schemas/events/list_events.py index d5d79e4..5538a26 100644 --- a/api/api/schemas/events/list_events.py +++ b/api/api/schemas/events/list_events.py @@ -3,7 +3,7 @@ from typing import Dict, Any from datetime import datetime from api.schemas.base import Base -from api.db.tables.events import EventState,EventStatus +from api.db.tables.events import EventState, EventStatus class ListEvent(Base): diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py index 5c0438e..b6ebba7 100644 --- a/api/api/services/update_data_validation.py +++ b/api/api/services/update_data_validation.py @@ -75,6 +75,7 @@ def update_key_data_changes(update_data: AccountKeyringUpdate, key) -> Optional[ return changes if changes else None + def update_listevents_data_changes(update_data: ListEventUpdate, listevents) -> Optional[dict]: """ Сравнивает данные для обновления с текущими значениями listevents. diff --git a/api/api/services/user_role_validation.py b/api/api/services/user_role_validation.py index fce09c8..8414ae9 100644 --- a/api/api/services/user_role_validation.py +++ b/api/api/services/user_role_validation.py @@ -12,16 +12,20 @@ async def db_user_role_validation(connection, current_user): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") return authorize_user -async def db_user_role_validation_for_listevents_by_listevent_id(connection, current_user,current_listevents_creator_id): + +async def db_user_role_validation_for_listevents_by_listevent_id( + connection, current_user, current_listevents_creator_id +): authorize_user = await get_user_by_login(connection, current_user) if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: if authorize_user.id != current_listevents_creator_id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You do not have enough permissions") return authorize_user + async def db_user_role_validation_for_listevents(connection, current_user): authorize_user = await get_user_by_login(connection, current_user) if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: - return authorize_user,False + return authorize_user, False else: - return authorize_user,True + return authorize_user, True From e0887c240ffb232fe50807689dd102a526a4d16f Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Sun, 27 Jul 2025 22:17:36 +0500 Subject: [PATCH 09/16] feat: CRUD ProcessSchema --- api/api/db/logic/listevents.py | 2 +- api/api/db/logic/processschema.py | 184 +++++++++++++++++++ api/api/db/tables/events.py | 3 +- api/api/db/tables/process.py | 3 +- api/api/endpoints/__init__.py | 3 +- api/api/endpoints/listevents.py | 28 +-- api/api/endpoints/processschema.py | 167 +++++++++++++++++ api/api/endpoints/profile.py | 4 - api/api/schemas/endpoints/account_keyring.py | 3 - api/api/schemas/endpoints/process_schema.py | 36 ++++ api/api/schemas/process/node_link.py | 11 +- api/api/schemas/process/process_schema.py | 12 +- api/api/schemas/process/ps_node.py | 15 +- api/api/services/update_data_validation.py | 36 +++- api/api/services/user_role_validation.py | 4 +- 15 files changed, 449 insertions(+), 62 deletions(-) create mode 100644 api/api/db/logic/processschema.py create mode 100644 api/api/endpoints/processschema.py create mode 100644 api/api/schemas/endpoints/process_schema.py diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index f667809..c318195 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -31,7 +31,7 @@ async def get_listevents_page_by_creator_id( list_events_table.c.title, list_events_table.c.creator_id, list_events_table.c.created_at, - list_events_table.c.schema_, + list_events_table.c.schema, list_events_table.c.state, list_events_table.c.status, ) diff --git a/api/api/db/logic/processschema.py b/api/api/db/logic/processschema.py new file mode 100644 index 0000000..5f34392 --- /dev/null +++ b/api/api/db/logic/processschema.py @@ -0,0 +1,184 @@ +from typing import Optional +import math + +from datetime import datetime, timezone + +from sqlalchemy import insert, select, func +from sqlalchemy.ext.asyncio import AsyncConnection +from enum import Enum + +from api.db.tables.process import process_schema_table + +from api.schemas.process.process_schema import ProcessSchema + +from api.schemas.endpoints.process_schema import all_process_schema_adapter, AllProcessSchemaResponse + +async def get_processschema_page_by_creator_id( + connection: AsyncConnection, creator_id: int, page: int, limit: int +) -> Optional[AllProcessSchemaResponse]: + """ + Получает список событий заданного создателя по значениям page и limit и creator_id. + """ + + first_schema = page * limit - limit + query = ( + select( + process_schema_table.c.id, + process_schema_table.c.title, + process_schema_table.c.description, + process_schema_table.c.owner_id, + process_schema_table.c.creator_id, + process_schema_table.c.created_at, + process_schema_table.c.settings, + process_schema_table.c.status, + ) + .where(process_schema_table.c.creator_id == creator_id) + .order_by(process_schema_table.c.id) + .offset(first_schema) + .limit(limit) + ) + + count_query = ( + select(func.count()) + .select_from(process_schema_table) + .where(process_schema_table.c.creator_id == creator_id) + ) + + result = await connection.execute(query) + count_result = await connection.execute(count_query) + + events_data = result.mappings().all() + total_count = count_result.scalar() + total_pages = math.ceil(total_count / limit) + + validated_process_schema = all_process_schema_adapter.validate_python(events_data) + + return AllProcessSchemaResponse( + process_schema=validated_process_schema, + amount_count=total_count, + amount_pages=total_pages, + current_page=page, + limit=limit, + ) + + +async def get_processschema_page(connection: AsyncConnection, page, limit) -> Optional[AllProcessSchemaResponse]: + """ + Получает список событий заданного создателя по значениям page и limit. + """ + + first_schema = page * limit - (limit) + + query = ( + select( + process_schema_table.c.id, + process_schema_table.c.title, + process_schema_table.c.description, + process_schema_table.c.owner_id, + process_schema_table.c.creator_id, + process_schema_table.c.created_at, + process_schema_table.c.settings, + process_schema_table.c.status, + ) + .order_by(process_schema_table.c.id) + .offset(first_schema) + .limit(limit) + ) + + count_query = select(func.count()).select_from(process_schema_table) + + result = await connection.execute(query) + count_result = await connection.execute(count_query) + + events_data = result.mappings().all() + total_count = count_result.scalar() + total_pages = math.ceil(total_count / limit) + + + validated_process_schema = all_process_schema_adapter.validate_python(events_data) + + return AllProcessSchemaResponse( + process_schema=validated_process_schema, + amount_count=total_count, + amount_pages=total_pages, + current_page=page, + limit=limit, + ) + + + +async def get_processschema_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]: + """ + Получает process schema по title. + """ + query = select(process_schema_table).where(process_schema_table.c.title == title) + + processschema_db_cursor = await connection.execute(query) + processschema_db = processschema_db_cursor.one_or_none() + + if not processschema_db: + return None + + processschema_data = { + column.name: ( + getattr(processschema_db, column.name).name + if isinstance(getattr(processschema_db, column.name), Enum) + else getattr(processschema_db, column.name) + ) + for column in process_schema_table.columns + } + + return ProcessSchema.model_validate(processschema_data) + +async def get_processschema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]: + """ + Получает processschema по id. + """ + query = select(process_schema_table).where(process_schema_table.c.id == id) + + processschema_db_cursor = await connection.execute(query) + processschema_db = processschema_db_cursor.one_or_none() + + if not processschema_db: + return None + + processschema_data = { + column.name: ( + getattr(processschema_db, column.name).name + if isinstance(getattr(processschema_db, column.name), Enum) + else getattr(processschema_db, column.name) + ) + for column in process_schema_table.columns + } + + return ProcessSchema.model_validate(processschema_data) + +async def update_processschema_by_id(connection: AsyncConnection, update_values, processschema): + """ + Вносит изменеия в нужное поле таблицы process_schema_table. + """ + await connection.execute( + process_schema_table.update().where(process_schema_table.c.id == processschema.id).values(**update_values) + ) + + await connection.commit() + +async def create_processschema(connection: AsyncConnection, processschema: ProcessSchema, creator_id: int) -> Optional[ProcessSchema]: + """ + Создает нове поле в таблице process_schema_table. + """ + query = insert(process_schema_table).values( + title=processschema.title, + description=processschema.description, + owner_id=processschema.owner_id, + creator_id=creator_id, + created_at=datetime.now(timezone.utc), + settings=processschema.settings, + status=processschema.status.value, + ) + + await connection.execute(query) + + await connection.commit() + + return processschema diff --git a/api/api/db/tables/events.py b/api/api/db/tables/events.py index fba2e58..8b60caf 100644 --- a/api/api/db/tables/events.py +++ b/api/api/db/tables/events.py @@ -1,8 +1,7 @@ import enum -from sqlalchemy import Table, Column, Integer, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index +from sqlalchemy import Table, Column, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime from sqlalchemy.sql import func -from enum import Enum, auto from api.db.sql_types import UnsignedInt diff --git a/api/api/db/tables/process.py b/api/api/db/tables/process.py index 379663c..7f9beec 100644 --- a/api/api/db/tables/process.py +++ b/api/api/db/tables/process.py @@ -3,7 +3,6 @@ import enum from sqlalchemy import ( Table, Column, - Integer, String, Text, Enum as SQLAEnum, @@ -14,7 +13,7 @@ from sqlalchemy import ( PrimaryKeyConstraint, ) from sqlalchemy.sql import func -from enum import Enum, auto +from enum import Enum from api.db.sql_types import UnsignedInt diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index a02a1c5..d0ecfc0 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -3,8 +3,9 @@ from api.endpoints.profile import api_router as profile_router from api.endpoints.account import api_router as account_router from api.endpoints.keyring import api_router as keyring_router from api.endpoints.listevents import api_router as listevents_router +from api.endpoints.processschema import api_router as processschema_router -list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router] +list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router,processschema_router] __all__ = [ "list_of_routes", diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py index 0a5a0f7..d93274f 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/listevents.py @@ -32,8 +32,8 @@ from api.schemas.endpoints.list_events import ListEventUpdate, AllListEventRespo from api.services.auth import get_current_user from api.services.user_role_validation import ( - db_user_role_validation_for_listevents_by_listevent_id, - db_user_role_validation_for_listevents, + db_user_role_validation_for_listevents_and_processschema_by_listevent_id, + db_user_role_validation_for_listevents_and_processschema, ) from api.services.update_data_validation import update_listevents_data_changes @@ -51,22 +51,22 @@ async def get_all_list_events( connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - authorize_user, page_flag = await db_user_role_validation_for_listevents(connection, current_user) + authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) if page_flag: - list_eventslist = await get_listevents_page(connection, page, limit) - print(list_eventslist) - if list_eventslist is None: + list_eventspage = await get_listevents_page(connection, page, limit) + + if list_eventspage is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - return list_eventslist + return list_eventspage else: - list_events_list = await get_listevents_page_by_creator_id(connection, authorize_user.id, page, limit) + list_events_page = await get_listevents_page_by_creator_id(connection, authorize_user.id, page, limit) - if list_events_list is None: + if list_events_page is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - return list_events_list + return list_events_page @api_router.get("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) @@ -80,7 +80,7 @@ async def get_list_events( if listevents_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_by_listevent_id( + authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( connection, current_user, listevents_validation.creator_id ) @@ -111,7 +111,7 @@ async def create_list_events( @api_router.put("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) -async def update_listevents( +async def update_list_events( listevents_id: int, listevents_update: ListEventUpdate, connection: AsyncConnection = Depends(get_connection_dep), @@ -122,7 +122,7 @@ async def update_listevents( if listevents_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_by_listevent_id( + authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( connection, current_user, listevents_validation.creator_id ) @@ -151,7 +151,7 @@ async def delete_list_events( if listevents_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_by_listevent_id( + authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( connection, current_user, listevents_validation.creator_id ) diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/processschema.py new file mode 100644 index 0000000..e0e67f8 --- /dev/null +++ b/api/api/endpoints/processschema.py @@ -0,0 +1,167 @@ +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.db.logic.processschema import ( + get_processschema_by_title, + create_processschema, + get_processschema_by_id, + update_processschema_by_id, + get_processschema_page_by_creator_id, + get_processschema_page +) + +from api.schemas.process.process_schema import ProcessSchema + +from api.db.tables.process import ProcessStatus + +from api.schemas.base import bearer_schema + +from api.schemas.endpoints.process_schema import ProcessSchemaUpdate, AllProcessSchemaResponse + +from api.services.auth import get_current_user + +from api.services.user_role_validation import ( + db_user_role_validation_for_listevents_and_processschema_by_listevent_id, + db_user_role_validation_for_listevents_and_processschema, +) +from api.services.update_data_validation import update_processschema_data_changes + + +api_router = APIRouter( + prefix="/processschema", + tags=["process schema"], +) + + + +@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllProcessSchemaResponse) +async def get_all_process_schema( + page: int = 1, + limit: int = 10, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) + + if page_flag: + process_schemapage = await get_processschema_page(connection, page, limit) + + if process_schemapage is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + + return process_schemapage + else: + process_schema_page = await get_processschema_page_by_creator_id(connection, authorize_user.id, page, limit) + + if process_schema_page is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + + return process_schema_page + + +@api_router.get("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +async def get_process_schema( + processschema_id: int, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + processschema_validation = await get_processschema_by_id(connection, processschema_id) + + if processschema_validation is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + + authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( + connection, current_user, processschema_validation.creator_id + ) + + if processschema_id is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + + return processschema_validation + +@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +async def create_process_schema( + processschema: ProcessSchemaUpdate, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + user_validation = await get_user_by_login(connection, current_user) + processschema_validation = await get_processschema_by_title(connection, processschema.title) + + if processschema_validation is None: + await create_processschema(connection, processschema, user_validation.id) + processschema_new = await get_processschema_by_title(connection, processschema.title) + return processschema_new + + else: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, detail="An process schema with this information already exists." + ) + + +@api_router.put("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +async def update_process_schema( + processschema_id: int, + processschema_update: ProcessSchemaUpdate, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + processschema_validation = await get_processschema_by_id(connection, processschema_id) + + if processschema_validation is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + + authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( + connection, current_user, processschema_validation.creator_id + ) + + update_values = update_processschema_data_changes(processschema_update, processschema_validation) + + if update_values is None: + return processschema_validation + + processschema_update_data = ProcessSchema.model_validate({**processschema_validation.model_dump(), **update_values}) + + await update_processschema_by_id(connection, update_values, processschema_validation) + + processschema = await get_processschema_by_id(connection, processschema_id) + + return processschema + +@api_router.delete("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +async def delete_process_schema( + processschema_id: int, + connection: AsyncConnection = Depends(get_connection_dep), + current_user=Depends(get_current_user), +): + processschema_validation = await get_processschema_by_id(connection, processschema_id) + + if processschema_validation is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + + authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( + connection, current_user, processschema_validation.creator_id + ) + + processschema_update = ProcessSchemaUpdate(status=ProcessStatus.DELETED.value) + + update_values = update_processschema_data_changes(processschema_update, processschema_validation) + + if update_values is None: + return processschema_validation + + await update_processschema_by_id(connection, update_values, processschema_validation) + + processschema = await get_processschema_by_id(connection, processschema_id) + + return processschema diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index 8f13a98..43ecf7c 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -1,11 +1,7 @@ from fastapi import ( APIRouter, - Body, Depends, - Form, HTTPException, - Request, - Response, status, ) diff --git a/api/api/schemas/endpoints/account_keyring.py b/api/api/schemas/endpoints/account_keyring.py index 382c9e8..49eab9e 100644 --- a/api/api/schemas/endpoints/account_keyring.py +++ b/api/api/schemas/endpoints/account_keyring.py @@ -1,9 +1,6 @@ -import datetime from typing import Optional from pydantic import Field -from datetime import datetime from api.db.tables.account import KeyType, KeyStatus - from api.schemas.base import Base diff --git a/api/api/schemas/endpoints/process_schema.py b/api/api/schemas/endpoints/process_schema.py new file mode 100644 index 0000000..3ba927c --- /dev/null +++ b/api/api/schemas/endpoints/process_schema.py @@ -0,0 +1,36 @@ +from pydantic import Field, TypeAdapter +from typing import Optional, Dict, Any, List +from datetime import datetime + + +from api.schemas.base import Base +from api.db.tables.process import ProcessStatus + + +class ProcessSchemaUpdate(Base): + title: Optional[str] = Field(None, max_length=100) + description: Optional[str] = None + owner_id: Optional[int] = None + settings: Optional[Dict[str, Any]] = None + status: Optional[ProcessStatus] = None + +class AllProcessSchema(Base): + id: int + title: str = Field(..., max_length=100) + description: str + owner_id: int + creator_id: int + created_at: datetime + settings: Dict[str, Any] + status: ProcessStatus + + +class AllProcessSchemaResponse(Base): + process_schema: List[AllProcessSchema] + amount_count: int + amount_pages: int + current_page: int + limit: int + + +all_process_schema_adapter = TypeAdapter(List[AllProcessSchema]) diff --git a/api/api/schemas/process/node_link.py b/api/api/schemas/process/node_link.py index f67a9f9..5ad9e1d 100644 --- a/api/api/schemas/process/node_link.py +++ b/api/api/schemas/process/node_link.py @@ -1,16 +1,9 @@ from pydantic import Field from typing import Dict, Any from datetime import datetime -from enum import Enum from api.schemas.base import Base - - -class Status(Enum): - ACTIVE = "Active" - STOPPING = "Stopping" - STOPPED = "Stopped" - DELETED = "Deleted" +from api.db.tables.process import NodeStatus class MyModel(Base): @@ -21,4 +14,4 @@ class MyModel(Base): settings: Dict[str, Any] creator_id: int created_at: datetime - status: Status + status: NodeStatus diff --git a/api/api/schemas/process/process_schema.py b/api/api/schemas/process/process_schema.py index 70f670b..364a624 100644 --- a/api/api/schemas/process/process_schema.py +++ b/api/api/schemas/process/process_schema.py @@ -1,17 +1,9 @@ from pydantic import Field from typing import Dict, Any from datetime import datetime -from enum import Enum from api.schemas.base import Base - - -class Status(Enum): - ACTIVE = "Active" - STOPPING = "Stopping" - STOPPED = "Stopped" - DELETED = "Deleted" - +from api.db.tables.process import ProcessStatus class ProcessSchema(Base): id: int @@ -21,4 +13,4 @@ class ProcessSchema(Base): creator_id: int created_at: datetime settings: Dict[str, Any] - status: Status + status: ProcessStatus diff --git a/api/api/schemas/process/ps_node.py b/api/api/schemas/process/ps_node.py index 0a47f38..3e75c6c 100644 --- a/api/api/schemas/process/ps_node.py +++ b/api/api/schemas/process/ps_node.py @@ -1,19 +1,8 @@ from datetime import datetime from typing import Dict, Any -from enum import Enum from api.schemas.base import Base - - -class NodeType(Enum): - pass - - -class Status(Enum): - ACTIVE = "Active" - DISABLED = "Disabled" - DELETED = "Deleted" - +from api.db.tables.process import NodeType,NodeStatus class Ps_Node(Base): id: int @@ -22,4 +11,4 @@ class Ps_Node(Base): settings: dict creator_id: Dict[str, Any] created_at: datetime - status: Status + status: NodeStatus diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py index b6ebba7..7b114a9 100644 --- a/api/api/services/update_data_validation.py +++ b/api/api/services/update_data_validation.py @@ -6,7 +6,8 @@ from api.schemas.endpoints.account_keyring import AccountKeyringUpdate from api.db.tables.account import AccountRole, AccountStatus from api.schemas.endpoints.list_events import ListEventUpdate from api.db.tables.events import EventState, EventStatus - +from api.schemas.endpoints.process_schema import ProcessSchemaUpdate +from api.db.tables.process import ProcessStatus def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: """ @@ -108,3 +109,36 @@ def update_listevents_data_changes(update_data: ListEventUpdate, listevents) -> changes[field] = new_value return changes if changes else None + +def update_processschema_data_changes(update_data: ProcessSchemaUpdate, processschema) -> Optional[dict]: + """ + Сравнивает данные для обновления с текущими значениями processschema. + Возвращает: + - None, если нет изменений + - Словарь {поле: новое_значение} для измененных полей + """ + update_values = {} + changes = {} + + for field, value in update_data.model_dump(exclude_unset=True).items(): + if value is None: + continue + + if isinstance(value, (ProcessStatus)): + update_values[field] = value.value + else: + update_values[field] = value + + for field, new_value in update_values.items(): + if not hasattr(processschema, field): + continue + + current_value = getattr(processschema, field) + + if isinstance(current_value, Enum): + current_value = current_value.value + + if current_value != new_value: + changes[field] = new_value + + return changes if changes else None diff --git a/api/api/services/user_role_validation.py b/api/api/services/user_role_validation.py index 8414ae9..657bd7e 100644 --- a/api/api/services/user_role_validation.py +++ b/api/api/services/user_role_validation.py @@ -13,7 +13,7 @@ async def db_user_role_validation(connection, current_user): return authorize_user -async def db_user_role_validation_for_listevents_by_listevent_id( +async def db_user_role_validation_for_listevents_and_processschema_by_listevent_id( connection, current_user, current_listevents_creator_id ): authorize_user = await get_user_by_login(connection, current_user) @@ -23,7 +23,7 @@ async def db_user_role_validation_for_listevents_by_listevent_id( return authorize_user -async def db_user_role_validation_for_listevents(connection, current_user): +async def db_user_role_validation_for_listevents_and_processschema(connection, current_user): authorize_user = await get_user_by_login(connection, current_user) if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: return authorize_user, False From b82960faf3779ed0a865ad2659aa1cc9671fa7bd Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Tue, 29 Jul 2025 22:57:31 +0500 Subject: [PATCH 10/16] fix: name,updated data, db data mapping --- api/api/db/logic/account.py | 13 ++----- api/api/db/logic/keyring.py | 13 ++----- api/api/db/logic/listevents.py | 27 ++++----------- api/api/db/logic/processschema.py | 43 +++++++----------------- api/api/endpoints/account.py | 15 ++++----- api/api/endpoints/keyring.py | 14 ++++---- api/api/endpoints/listevents.py | 20 +++++------ api/api/endpoints/processschema.py | 54 ++++++++++++++---------------- api/api/endpoints/profile.py | 13 +++---- 9 files changed, 77 insertions(+), 135 deletions(-) diff --git a/api/api/db/logic/account.py b/api/api/db/logic/account.py index 2efb0af..21a73c8 100644 --- a/api/api/db/logic/account.py +++ b/api/api/db/logic/account.py @@ -76,19 +76,10 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional query = select(account_table).where(account_table.c.login == login) user_db_cursor = await connection.execute(query) - user_db = user_db_cursor.one_or_none() - - if not user_db: + user_data = user_db_cursor.mappings().one_or_none() + if not user_data: return None - user_data = { - column.name: ( - getattr(user_db, column.name).name - if isinstance(getattr(user_db, column.name), Enum) - else getattr(user_db, column.name) - ) - for column in account_table.columns - } return User.model_validate(user_data) diff --git a/api/api/db/logic/keyring.py b/api/api/db/logic/keyring.py index ad3de1b..f4dd70d 100644 --- a/api/api/db/logic/keyring.py +++ b/api/api/db/logic/keyring.py @@ -18,20 +18,11 @@ async def get_key_by_id(connection: AsyncConnection, key_id: str) -> Optional[Ac query = select(account_keyring_table).where(account_keyring_table.c.key_id == key_id) user_db_cursor = await connection.execute(query) - user_db = user_db_cursor.one_or_none() - if not user_db: + user_data = user_db_cursor.mappings().one_or_none() + if not user_data: return None - user_data = { - column.name: ( - getattr(user_db, column.name).name - if isinstance(getattr(user_db, column.name), Enum) - else getattr(user_db, column.name) - ) - for column in account_keyring_table.columns - } - return AccountKeyring.model_validate(user_data) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index c318195..e28589b 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -117,19 +117,13 @@ async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Opti query = select(list_events_table).where(list_events_table.c.name == name) listevents_db_cursor = await connection.execute(query) - listevents_db = listevents_db_cursor.one_or_none() - if not listevents_db: + listevents_data = listevents_db_cursor.mappings().one_or_none() + if not listevents_data: return None - listevents_data = { - column.name: ( - getattr(listevents_db, column.name).name - if isinstance(getattr(listevents_db, column.name), Enum) - else getattr(listevents_db, column.name) - ) - for column in list_events_table.columns - } + + return ListEvent.model_validate(listevents_data) @@ -141,20 +135,11 @@ async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional query = select(list_events_table).where(list_events_table.c.id == id) listevents_db_cursor = await connection.execute(query) - listevents_db = listevents_db_cursor.one_or_none() - if not listevents_db: + listevents_data = listevents_db_cursor.mappings().one_or_none() + if not listevents_data: return None - listevents_data = { - column.name: ( - getattr(listevents_db, column.name).name - if isinstance(getattr(listevents_db, column.name), Enum) - else getattr(listevents_db, column.name) - ) - for column in list_events_table.columns - } - return ListEvent.model_validate(listevents_data) diff --git a/api/api/db/logic/processschema.py b/api/api/db/logic/processschema.py index 5f34392..f048275 100644 --- a/api/api/db/logic/processschema.py +++ b/api/api/db/logic/processschema.py @@ -13,11 +13,11 @@ from api.schemas.process.process_schema import ProcessSchema from api.schemas.endpoints.process_schema import all_process_schema_adapter, AllProcessSchemaResponse -async def get_processschema_page_by_creator_id( +async def get_process_schema_page_by_creator_id( connection: AsyncConnection, creator_id: int, page: int, limit: int ) -> Optional[AllProcessSchemaResponse]: """ - Получает список событий заданного создателя по значениям page и limit и creator_id. + Получает список схем процессов по значениям page и limit и creator_id. """ first_schema = page * limit - limit @@ -62,9 +62,9 @@ async def get_processschema_page_by_creator_id( ) -async def get_processschema_page(connection: AsyncConnection, page, limit) -> Optional[AllProcessSchemaResponse]: +async def get_process_schema_page(connection: AsyncConnection, page, limit) -> Optional[AllProcessSchemaResponse]: """ - Получает список событий заданного создателя по значениям page и limit. + Получает список схем процессов по значениям page и limit. """ first_schema = page * limit - (limit) @@ -107,53 +107,36 @@ async def get_processschema_page(connection: AsyncConnection, page, limit) -> Op -async def get_processschema_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]: +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) processschema_db_cursor = await connection.execute(query) - processschema_db = processschema_db_cursor.one_or_none() - if not processschema_db: + processschema_data = processschema_db_cursor.mappings().one_or_none() + if not processschema_data: return None - processschema_data = { - column.name: ( - getattr(processschema_db, column.name).name - if isinstance(getattr(processschema_db, column.name), Enum) - else getattr(processschema_db, column.name) - ) - for column in process_schema_table.columns - } - return ProcessSchema.model_validate(processschema_data) -async def get_processschema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]: +async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]: """ Получает processschema по id. """ query = select(process_schema_table).where(process_schema_table.c.id == id) processschema_db_cursor = await connection.execute(query) - processschema_db = processschema_db_cursor.one_or_none() - if not processschema_db: + + processschema_data = processschema_db_cursor.mappings().one_or_none() + if not processschema_data: return None - processschema_data = { - column.name: ( - getattr(processschema_db, column.name).name - if isinstance(getattr(processschema_db, column.name), Enum) - else getattr(processschema_db, column.name) - ) - for column in process_schema_table.columns - } - return ProcessSchema.model_validate(processschema_data) -async def update_processschema_by_id(connection: AsyncConnection, update_values, processschema): +async def update_process_schema_by_id(connection: AsyncConnection, update_values, processschema): """ Вносит изменеия в нужное поле таблицы process_schema_table. """ @@ -163,7 +146,7 @@ async def update_processschema_by_id(connection: AsyncConnection, update_values, await connection.commit() -async def create_processschema(connection: AsyncConnection, processschema: ProcessSchema, creator_id: int) -> Optional[ProcessSchema]: +async def create_process_schema(connection: AsyncConnection, processschema: ProcessSchema, creator_id: int) -> Optional[ProcessSchema]: """ Создает нове поле в таблице process_schema_table. """ diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 5ce0da4..daa0d93 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -98,14 +98,13 @@ async def update_account( if user_update.password is not None: await update_password_key(connection, user.id, user_update.password) - update_values = update_user_data_changes(user_update, user) - if update_values is None: + updated_values = user_update.model_dump(by_alias=True, exclude_none=True) + + if not updated_values: return user - user_update_data = UserUpdate.model_validate({**user.model_dump(), **update_values}) - - await update_user_by_id(connection, update_values, user) + await update_user_by_id(connection, updated_values, user) user = await get_user_by_id(connection, user_id) @@ -126,12 +125,12 @@ async def delete_account( user_update = UserUpdate(status=AccountStatus.DELETED.value) - update_values = update_user_data_changes(user_update, user) + updated_values = user_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return user - await update_user_by_id(connection, update_values, user) + await update_user_by_id(connection, updated_values, user) user = await get_user_by_id(connection, user_id) diff --git a/api/api/endpoints/keyring.py b/api/api/endpoints/keyring.py index 3f09f61..20990c8 100644 --- a/api/api/endpoints/keyring.py +++ b/api/api/endpoints/keyring.py @@ -87,14 +87,12 @@ async def update_keyring( if keyring is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="keyring not found") - update_values = update_key_data_changes(keyring_update, keyring) + updated_values = keyring_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return keyring - keyring_update_data = AccountKeyring.model_validate({**keyring.model_dump(), **update_values}) - - await update_key_by_id(connection, update_values, keyring) + await update_key_by_id(connection, updated_values, keyring) keyring = await get_key_by_id(connection, key_id) @@ -116,12 +114,12 @@ async def delete_keyring( keyring_update = AccountKeyringUpdate(status=KeyStatus.DELETED.value) - update_values = update_key_data_changes(keyring_update, keyring) + updated_values = keyring_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return keyring - await update_key_by_id(connection, update_values, keyring) + await update_key_by_id(connection, updated_values, keyring) keyring = await get_key_by_id(connection, key_id) diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py index d93274f..914d37d 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/listevents.py @@ -54,12 +54,12 @@ async def get_all_list_events( authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) if page_flag: - list_eventspage = await get_listevents_page(connection, page, limit) + list_events_page = await get_listevents_page(connection, page, limit) - if list_eventspage is None: + if list_events_page is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - return list_eventspage + return list_events_page else: list_events_page = await get_listevents_page_by_creator_id(connection, authorize_user.id, page, limit) @@ -126,14 +126,12 @@ async def update_list_events( connection, current_user, listevents_validation.creator_id ) - update_values = update_listevents_data_changes(listevents_update, listevents_validation) + updated_values = listevents_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return listevents_validation - listevents_update_data = ListEvent.model_validate({**listevents_validation.model_dump(), **update_values}) - - await update_listevents_by_id(connection, update_values, listevents_validation) + await update_listevents_by_id(connection, updated_values, listevents_validation) listevents = await get_listevents_by_id(connection, listevents_id) @@ -157,12 +155,12 @@ async def delete_list_events( listevents_update = ListEventUpdate(status=EventStatus.DELETED.value) - update_values = update_listevents_data_changes(listevents_update, listevents_validation) + updated_values = listevents_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return listevents_validation - await update_listevents_by_id(connection, update_values, listevents_validation) + await update_listevents_by_id(connection, updated_values, listevents_validation) listevents = await get_listevents_by_id(connection, listevents_id) diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/processschema.py index e0e67f8..5e3401c 100644 --- a/api/api/endpoints/processschema.py +++ b/api/api/endpoints/processschema.py @@ -12,12 +12,12 @@ from api.db.connection.session import get_connection_dep from api.db.logic.account import get_user_by_login from api.db.logic.processschema import ( - get_processschema_by_title, - create_processschema, - get_processschema_by_id, - update_processschema_by_id, - get_processschema_page_by_creator_id, - get_processschema_page + get_process_schema_by_title, + create_process_schema, + get_process_schema_by_id, + update_process_schema_by_id, + get_process_schema_page_by_creator_id, + get_process_schema_page ) from api.schemas.process.process_schema import ProcessSchema @@ -42,8 +42,6 @@ api_router = APIRouter( tags=["process schema"], ) - - @api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllProcessSchemaResponse) async def get_all_process_schema( page: int = 1, @@ -54,14 +52,14 @@ async def get_all_process_schema( authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) if page_flag: - process_schemapage = await get_processschema_page(connection, page, limit) + process_schema_page = await get_process_schema_page(connection, page, limit) - if process_schemapage is None: + if process_schema_page is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") - return process_schemapage + return process_schema_page else: - process_schema_page = await get_processschema_page_by_creator_id(connection, authorize_user.id, page, limit) + process_schema_page = await get_process_schema_page_by_creator_id(connection, authorize_user.id, page, limit) if process_schema_page is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") @@ -75,7 +73,7 @@ async def get_process_schema( connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - processschema_validation = await get_processschema_by_id(connection, processschema_id) + processschema_validation = await get_process_schema_by_id(connection, processschema_id) if processschema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") @@ -90,17 +88,17 @@ async def get_process_schema( return processschema_validation @api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) -async def create_process_schema( +async def create_processschema( processschema: ProcessSchemaUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): user_validation = await get_user_by_login(connection, current_user) - processschema_validation = await get_processschema_by_title(connection, processschema.title) + processschema_validation = await get_process_schema_by_title(connection, processschema.title) if processschema_validation is None: - await create_processschema(connection, processschema, user_validation.id) - processschema_new = await get_processschema_by_title(connection, processschema.title) + await create_process_schema(connection, processschema, user_validation.id) + processschema_new = await get_process_schema_by_title(connection, processschema.title) return processschema_new else: @@ -116,7 +114,7 @@ async def update_process_schema( connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - processschema_validation = await get_processschema_by_id(connection, processschema_id) + processschema_validation = await get_process_schema_by_id(connection, processschema_id) if processschema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") @@ -125,16 +123,14 @@ async def update_process_schema( connection, current_user, processschema_validation.creator_id ) - update_values = update_processschema_data_changes(processschema_update, processschema_validation) + updated_values = processschema_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return processschema_validation - processschema_update_data = ProcessSchema.model_validate({**processschema_validation.model_dump(), **update_values}) + await update_process_schema_by_id(connection, updated_values, processschema_validation) - await update_processschema_by_id(connection, update_values, processschema_validation) - - processschema = await get_processschema_by_id(connection, processschema_id) + processschema = await get_process_schema_by_id(connection, processschema_id) return processschema @@ -144,7 +140,7 @@ async def delete_process_schema( connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - processschema_validation = await get_processschema_by_id(connection, processschema_id) + processschema_validation = await get_process_schema_by_id(connection, processschema_id) if processschema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") @@ -155,13 +151,13 @@ async def delete_process_schema( processschema_update = ProcessSchemaUpdate(status=ProcessStatus.DELETED.value) - update_values = update_processschema_data_changes(processschema_update, processschema_validation) + updated_values = processschema_update.model_dump(by_alias=True, exclude_none=True) - if update_values is None: + if not updated_values: return processschema_validation - await update_processschema_by_id(connection, update_values, processschema_validation) + await update_process_schema_by_id(connection, updated_values, processschema_validation) - processschema = await get_processschema_by_id(connection, processschema_id) + processschema = await get_process_schema_by_id(connection, processschema_id) return processschema diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index 43ecf7c..407e627 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -38,7 +38,7 @@ async def get_profile( @api_router.put("", dependencies=[Depends(bearer_schema)], response_model=User) async def update_profile( - user_updata: UserUpdate, + user_update: UserUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): @@ -46,15 +46,16 @@ async def update_profile( if user is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") - if user_updata.role == None and user_updata.login == None: - update_values = update_user_data_changes(user_updata, user) + if user_update.role is None and user_update.login is None: - if update_values is None: + updated_values = user_update.model_dump(by_alias=True, exclude_none=True) + + if updated_values is None: return user - await update_user_by_id(connection, update_values, user) + await update_user_by_id(connection, updated_values, user) - user = await get_user_by_id(connection, user.id) + user = await get_user_by_id(connection, user.id) return user else: From 2030d54b2cf9c243c71aae0f976ab7eff9d110fc Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Wed, 30 Jul 2025 14:04:59 +0500 Subject: [PATCH 11/16] fix: ruff format --- api/api/db/logic/account.py | 1 - api/api/db/logic/listevents.py | 3 --- api/api/db/logic/processschema.py | 15 ++++++++------- api/api/endpoints/__init__.py | 2 +- api/api/endpoints/account.py | 1 - api/api/endpoints/processschema.py | 5 ++++- api/api/endpoints/profile.py | 1 - api/api/schemas/endpoints/process_schema.py | 1 + api/api/schemas/process/process_schema.py | 1 + api/api/schemas/process/ps_node.py | 3 ++- api/api/services/update_data_validation.py | 2 ++ 11 files changed, 19 insertions(+), 16 deletions(-) diff --git a/api/api/db/logic/account.py b/api/api/db/logic/account.py index 21a73c8..f6b92fb 100644 --- a/api/api/db/logic/account.py +++ b/api/api/db/logic/account.py @@ -80,7 +80,6 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional if not user_data: return None - return User.model_validate(user_data) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index e28589b..d00818b 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -122,9 +122,6 @@ async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Opti if not listevents_data: return None - - - return ListEvent.model_validate(listevents_data) diff --git a/api/api/db/logic/processschema.py b/api/api/db/logic/processschema.py index f048275..d7cdffb 100644 --- a/api/api/db/logic/processschema.py +++ b/api/api/db/logic/processschema.py @@ -13,6 +13,7 @@ from api.schemas.process.process_schema import ProcessSchema from api.schemas.endpoints.process_schema import all_process_schema_adapter, AllProcessSchemaResponse + async def get_process_schema_page_by_creator_id( connection: AsyncConnection, creator_id: int, page: int, limit: int ) -> Optional[AllProcessSchemaResponse]: @@ -39,9 +40,7 @@ async def get_process_schema_page_by_creator_id( ) count_query = ( - select(func.count()) - .select_from(process_schema_table) - .where(process_schema_table.c.creator_id == creator_id) + select(func.count()).select_from(process_schema_table).where(process_schema_table.c.creator_id == creator_id) ) result = await connection.execute(query) @@ -94,7 +93,6 @@ async def get_process_schema_page(connection: AsyncConnection, page, limit) -> O total_count = count_result.scalar() total_pages = math.ceil(total_count / limit) - validated_process_schema = all_process_schema_adapter.validate_python(events_data) return AllProcessSchemaResponse( @@ -106,7 +104,6 @@ async def get_process_schema_page(connection: AsyncConnection, page, limit) -> O ) - async def get_process_schema_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]: """ Получает process schema по title. @@ -121,6 +118,7 @@ async def get_process_schema_by_title(connection: AsyncConnection, title: str) - return ProcessSchema.model_validate(processschema_data) + async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]: """ Получает processschema по id. @@ -129,13 +127,13 @@ async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Opti processschema_db_cursor = await connection.execute(query) - processschema_data = processschema_db_cursor.mappings().one_or_none() if not processschema_data: return None return ProcessSchema.model_validate(processschema_data) + async def update_process_schema_by_id(connection: AsyncConnection, update_values, processschema): """ Вносит изменеия в нужное поле таблицы process_schema_table. @@ -146,7 +144,10 @@ async def update_process_schema_by_id(connection: AsyncConnection, update_values await connection.commit() -async def create_process_schema(connection: AsyncConnection, processschema: ProcessSchema, creator_id: int) -> Optional[ProcessSchema]: + +async def create_process_schema( + connection: AsyncConnection, processschema: ProcessSchema, creator_id: int +) -> Optional[ProcessSchema]: """ Создает нове поле в таблице process_schema_table. """ diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index d0ecfc0..be25e82 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -5,7 +5,7 @@ from api.endpoints.keyring import api_router as keyring_router from api.endpoints.listevents import api_router as listevents_router from api.endpoints.processschema import api_router as processschema_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] __all__ = [ "list_of_routes", diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index daa0d93..0c46c7b 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -98,7 +98,6 @@ async def update_account( if user_update.password is not None: await update_password_key(connection, user.id, user_update.password) - updated_values = user_update.model_dump(by_alias=True, exclude_none=True) if not updated_values: diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/processschema.py index 5e3401c..6866bf7 100644 --- a/api/api/endpoints/processschema.py +++ b/api/api/endpoints/processschema.py @@ -17,7 +17,7 @@ from api.db.logic.processschema import ( get_process_schema_by_id, update_process_schema_by_id, get_process_schema_page_by_creator_id, - get_process_schema_page + get_process_schema_page, ) from api.schemas.process.process_schema import ProcessSchema @@ -42,6 +42,7 @@ api_router = APIRouter( tags=["process schema"], ) + @api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllProcessSchemaResponse) async def get_all_process_schema( page: int = 1, @@ -87,6 +88,7 @@ async def get_process_schema( return processschema_validation + @api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) async def create_processschema( processschema: ProcessSchemaUpdate, @@ -134,6 +136,7 @@ async def update_process_schema( return processschema + @api_router.delete("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) async def delete_process_schema( processschema_id: int, diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index 407e627..419ec18 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -47,7 +47,6 @@ async def update_profile( raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found") if user_update.role is None and user_update.login is None: - updated_values = user_update.model_dump(by_alias=True, exclude_none=True) if updated_values is None: diff --git a/api/api/schemas/endpoints/process_schema.py b/api/api/schemas/endpoints/process_schema.py index 3ba927c..6a06ce3 100644 --- a/api/api/schemas/endpoints/process_schema.py +++ b/api/api/schemas/endpoints/process_schema.py @@ -14,6 +14,7 @@ class ProcessSchemaUpdate(Base): settings: Optional[Dict[str, Any]] = None status: Optional[ProcessStatus] = None + class AllProcessSchema(Base): id: int title: str = Field(..., max_length=100) diff --git a/api/api/schemas/process/process_schema.py b/api/api/schemas/process/process_schema.py index 364a624..ad1f920 100644 --- a/api/api/schemas/process/process_schema.py +++ b/api/api/schemas/process/process_schema.py @@ -5,6 +5,7 @@ from datetime import datetime from api.schemas.base import Base from api.db.tables.process import ProcessStatus + class ProcessSchema(Base): id: int title: str = Field(..., max_length=100) diff --git a/api/api/schemas/process/ps_node.py b/api/api/schemas/process/ps_node.py index 3e75c6c..742c2d5 100644 --- a/api/api/schemas/process/ps_node.py +++ b/api/api/schemas/process/ps_node.py @@ -2,7 +2,8 @@ from datetime import datetime from typing import Dict, Any from api.schemas.base import Base -from api.db.tables.process import NodeType,NodeStatus +from api.db.tables.process import NodeType, NodeStatus + class Ps_Node(Base): id: int diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py index 7b114a9..5d9df38 100644 --- a/api/api/services/update_data_validation.py +++ b/api/api/services/update_data_validation.py @@ -9,6 +9,7 @@ from api.db.tables.events import EventState, EventStatus from api.schemas.endpoints.process_schema import ProcessSchemaUpdate from api.db.tables.process import ProcessStatus + def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: """ Сравнивает данные для обновления с текущими значениями пользователя. @@ -110,6 +111,7 @@ def update_listevents_data_changes(update_data: ListEventUpdate, listevents) -> return changes if changes else None + def update_processschema_data_changes(update_data: ProcessSchemaUpdate, processschema) -> Optional[dict]: """ Сравнивает данные для обновления с текущими значениями processschema. From e50bb324706ba7a37ff8b34fa362e46301f18a57 Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Thu, 31 Jul 2025 20:33:45 +0500 Subject: [PATCH 12/16] fix:api name "process-schema" --- api/api/endpoints/processschema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/processschema.py index 6866bf7..cd4b0ee 100644 --- a/api/api/endpoints/processschema.py +++ b/api/api/endpoints/processschema.py @@ -38,7 +38,7 @@ from api.services.update_data_validation import update_processschema_data_change api_router = APIRouter( - prefix="/processschema", + prefix="/process-schema", tags=["process schema"], ) From a9ecaadad63a5684634a6f06b409447e0adc4c1f Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Thu, 31 Jul 2025 21:53:33 +0500 Subject: [PATCH 13/16] feat: porcess-schema endpoint DTO --- api/api/db/logic/processschema.py | 129 ++++++++--------- api/api/endpoints/account.py | 1 - api/api/endpoints/keyring.py | 1 - api/api/endpoints/listevents.py | 2 +- api/api/endpoints/processschema.py | 52 ++++--- api/api/endpoints/profile.py | 1 - api/api/schemas/endpoints/process_schema.py | 8 ++ api/api/services/update_data_validation.py | 146 -------------------- 8 files changed, 110 insertions(+), 230 deletions(-) delete mode 100644 api/api/services/update_data_validation.py diff --git a/api/api/db/logic/processschema.py b/api/api/db/logic/processschema.py index d7cdffb..21c3763 100644 --- a/api/api/db/logic/processschema.py +++ b/api/api/db/logic/processschema.py @@ -3,94 +3,96 @@ import math from datetime import datetime, timezone -from sqlalchemy import insert, select, func +from sqlalchemy import insert, select, func,or_, and_, asc, desc from sqlalchemy.ext.asyncio import AsyncConnection -from enum import Enum from api.db.tables.process import process_schema_table from api.schemas.process.process_schema import ProcessSchema -from api.schemas.endpoints.process_schema import all_process_schema_adapter, AllProcessSchemaResponse +from api.schemas.endpoints.process_schema import all_process_schema_adapter, AllProcessSchemaResponse, ProcessSchemaFilterDTO -async def get_process_schema_page_by_creator_id( - connection: AsyncConnection, creator_id: int, page: int, limit: int -) -> Optional[AllProcessSchemaResponse]: +async def get_process_schema_page(connection: AsyncConnection, filter_dto: ProcessSchemaFilterDTO) -> Optional[AllProcessSchemaResponse]: """ - Получает список схем процессов по значениям page и limit и creator_id. + Получает список схем процессов с комплексной фильтрацией через DTO объект. """ - first_schema = page * limit - limit - query = ( - select( - process_schema_table.c.id, - process_schema_table.c.title, - process_schema_table.c.description, - process_schema_table.c.owner_id, - process_schema_table.c.creator_id, - process_schema_table.c.created_at, - process_schema_table.c.settings, - process_schema_table.c.status, + page = filter_dto.pagination.get('page', 1) + limit = filter_dto.pagination.get('limit', 10) + offset = (page - 1) * limit + + query = select( + process_schema_table.c.id, + process_schema_table.c.title, + process_schema_table.c.description, + process_schema_table.c.owner_id, + process_schema_table.c.creator_id, + process_schema_table.c.created_at, + process_schema_table.c.settings, + process_schema_table.c.status, + ) + + if filter_dto.search: + search_term = f"%{filter_dto.search}%" + query = query.where( + or_( + process_schema_table.c.title.ilike(search_term), + process_schema_table.c.description.ilike(search_term) + ) ) - .where(process_schema_table.c.creator_id == creator_id) - .order_by(process_schema_table.c.id) - .offset(first_schema) - .limit(limit) - ) - count_query = ( - select(func.count()).select_from(process_schema_table).where(process_schema_table.c.creator_id == creator_id) - ) + 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: + if len(values) == 1: + filter_conditions.append(column == values[0]) + else: + filter_conditions.append(column.in_(values)) - result = await connection.execute(query) - count_result = await connection.execute(count_query) + if filter_conditions: + query = query.where(and_(*filter_conditions)) - events_data = result.mappings().all() - total_count = count_result.scalar() - total_pages = math.ceil(total_count / limit) + if filter_dto.order: + order_field = filter_dto.order.get('field', 'id') + order_direction = filter_dto.order.get('direction', 'asc') - validated_process_schema = all_process_schema_adapter.validate_python(events_data) + column = getattr(process_schema_table.c, order_field, None) + if column is not None: + if order_direction.lower() == 'desc': + query = query.order_by(desc(column)) + else: + query = query.order_by(asc(column)) + else: + query = query.order_by(process_schema_table.c.id) - return AllProcessSchemaResponse( - process_schema=validated_process_schema, - amount_count=total_count, - amount_pages=total_pages, - current_page=page, - limit=limit, - ) - - -async def get_process_schema_page(connection: AsyncConnection, page, limit) -> Optional[AllProcessSchemaResponse]: - """ - Получает список схем процессов по значениям page и limit. - """ - - first_schema = page * limit - (limit) - - query = ( - select( - process_schema_table.c.id, - process_schema_table.c.title, - process_schema_table.c.description, - process_schema_table.c.owner_id, - process_schema_table.c.creator_id, - process_schema_table.c.created_at, - process_schema_table.c.settings, - process_schema_table.c.status, - ) - .order_by(process_schema_table.c.id) - .offset(first_schema) - .limit(limit) - ) + query = query.offset(offset).limit(limit) count_query = select(func.count()).select_from(process_schema_table) + if filter_dto.search: + search_term = f"%{filter_dto.search}%" + count_query = count_query.where( + or_( + process_schema_table.c.title.ilike(search_term), + process_schema_table.c.description.ilike(search_term) + ) + ) + + if filter_dto.filters and filter_conditions: + count_query = count_query.where(and_(*filter_conditions)) + result = await connection.execute(query) count_result = await connection.execute(count_query) events_data = result.mappings().all() total_count = count_result.scalar() + + if not total_count: + return None + total_pages = math.ceil(total_count / limit) validated_process_schema = all_process_schema_adapter.validate_python(events_data) @@ -103,7 +105,6 @@ async def get_process_schema_page(connection: AsyncConnection, page, limit) -> O limit=limit, ) - async def get_process_schema_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]: """ Получает process schema по title. diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index 0c46c7b..a66b683 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -20,7 +20,6 @@ from api.schemas.account.account import User from api.schemas.base import bearer_schema from api.schemas.endpoints.account import AllUser, AllUserResponse, UserCreate, UserUpdate from api.services.auth import get_current_user -from api.services.update_data_validation import update_user_data_changes from api.services.user_role_validation import db_user_role_validation api_router = APIRouter( diff --git a/api/api/endpoints/keyring.py b/api/api/endpoints/keyring.py index 20990c8..487627c 100644 --- a/api/api/endpoints/keyring.py +++ b/api/api/endpoints/keyring.py @@ -24,7 +24,6 @@ from api.schemas.account.account_keyring import AccountKeyring from api.services.auth import get_current_user from api.services.user_role_validation import db_user_role_validation -from api.services.update_data_validation import update_key_data_changes api_router = APIRouter( diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py index 914d37d..33bb4ec 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/listevents.py @@ -35,7 +35,7 @@ from api.services.user_role_validation import ( db_user_role_validation_for_listevents_and_processschema_by_listevent_id, db_user_role_validation_for_listevents_and_processschema, ) -from api.services.update_data_validation import update_listevents_data_changes + api_router = APIRouter( diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/processschema.py index cd4b0ee..5be73a9 100644 --- a/api/api/endpoints/processschema.py +++ b/api/api/endpoints/processschema.py @@ -3,8 +3,10 @@ from fastapi import ( Depends, HTTPException, status, + Query ) +from typing import Optional, Dict, Any, List from sqlalchemy.ext.asyncio import AsyncConnection from api.db.connection.session import get_connection_dep @@ -16,7 +18,6 @@ from api.db.logic.processschema import ( create_process_schema, get_process_schema_by_id, update_process_schema_by_id, - get_process_schema_page_by_creator_id, get_process_schema_page, ) @@ -26,7 +27,7 @@ from api.db.tables.process import ProcessStatus from api.schemas.base import bearer_schema -from api.schemas.endpoints.process_schema import ProcessSchemaUpdate, AllProcessSchemaResponse +from api.schemas.endpoints.process_schema import ProcessSchemaUpdate, AllProcessSchemaResponse, ProcessSchemaFilterDTO from api.services.auth import get_current_user @@ -34,7 +35,6 @@ from api.services.user_role_validation import ( db_user_role_validation_for_listevents_and_processschema_by_listevent_id, db_user_role_validation_for_listevents_and_processschema, ) -from api.services.update_data_validation import update_processschema_data_changes api_router = APIRouter( @@ -45,27 +45,47 @@ api_router = APIRouter( @api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllProcessSchemaResponse) async def get_all_process_schema( - page: int = 1, - limit: int = 10, + page: int = Query(1, description="Page number", gt=0), + limit: int = Query(10, description="Number of items per page", gt=0), + search: Optional[str] = Query(None, description="Search term to filter by title or description"), + order_field: Optional[str] = Query("id", description="Field to sort by"), + order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), + status_filter: Optional[List[str]] = Query(None, description="Filter by status"), + owner_id: Optional[List[str]] = Query(None, description="Filter by owner ID"), connection: AsyncConnection = Depends(get_connection_dep), + creator_id: Optional[int] = Query(None, description="Filter by creator ID"), current_user=Depends(get_current_user), ): + + filters = { + **({"status": status_filter} if status_filter else {}), + **({"owner_id": owner_id} if owner_id else {}), + **({"creator_id": [str(creator_id)]} if creator_id else {}), + } + + filter_dto = ProcessSchemaFilterDTO( + pagination={"page": page, "limit": limit}, + search=search, + order={"field": order_field, "direction": order_direction}, + filters=filters if filters else None + ) + authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) - if page_flag: - process_schema_page = await get_process_schema_page(connection, page, limit) + if not page_flag: + if filter_dto.filters is None: + filter_dto.filters = {} + filter_dto.filters["creator_id"] = [str(authorize_user.id)] - if process_schema_page is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") + process_schema_page = await get_process_schema_page(connection, filter_dto) - return process_schema_page - else: - process_schema_page = await get_process_schema_page_by_creator_id(connection, authorize_user.id, page, limit) + if process_schema_page is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Process schema not found" + ) - 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 process_schema_page @api_router.get("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) diff --git a/api/api/endpoints/profile.py b/api/api/endpoints/profile.py index 419ec18..2565936 100644 --- a/api/api/endpoints/profile.py +++ b/api/api/endpoints/profile.py @@ -12,7 +12,6 @@ from api.db.connection.session import get_connection_dep from api.db.logic.account import get_user_by_id, update_user_by_id, get_user_by_login from api.schemas.base import bearer_schema from api.services.auth import get_current_user -from api.services.update_data_validation import update_user_data_changes from api.schemas.endpoints.account import UserUpdate from api.schemas.account.account import User diff --git a/api/api/schemas/endpoints/process_schema.py b/api/api/schemas/endpoints/process_schema.py index 6a06ce3..f00b5df 100644 --- a/api/api/schemas/endpoints/process_schema.py +++ b/api/api/schemas/endpoints/process_schema.py @@ -35,3 +35,11 @@ class AllProcessSchemaResponse(Base): all_process_schema_adapter = TypeAdapter(List[AllProcessSchema]) + + +# DTO объект для фильтрации +class ProcessSchemaFilterDTO(Base): + pagination: Dict[str, int] # {page: 1, limit: 10} + search: Optional[str] = None + order: Optional[Dict[str, str]] = None # {field: "id", direction: "asc"} + filters: Optional[Dict[str, List[str]]] = None # {"status": ["active"], "owner_id": ["123"]} diff --git a/api/api/services/update_data_validation.py b/api/api/services/update_data_validation.py deleted file mode 100644 index 5d9df38..0000000 --- a/api/api/services/update_data_validation.py +++ /dev/null @@ -1,146 +0,0 @@ -from enum import Enum -from typing import Optional -from api.schemas.endpoints.account import UserUpdate -from api.db.tables.account import KeyType, KeyStatus -from api.schemas.endpoints.account_keyring import AccountKeyringUpdate -from api.db.tables.account import AccountRole, AccountStatus -from api.schemas.endpoints.list_events import ListEventUpdate -from api.db.tables.events import EventState, EventStatus -from api.schemas.endpoints.process_schema import ProcessSchemaUpdate -from api.db.tables.process import ProcessStatus - - -def update_user_data_changes(update_data: UserUpdate, user) -> Optional[dict]: - """ - Сравнивает данные для обновления с текущими значениями пользователя. - Возвращает: - - None, если нет изменений - - Словарь {поле: новое_значение} для измененных полей - """ - update_values = {} - changes = {} - - for field, value in update_data.model_dump(exclude_unset=True).items(): - if value is None: - continue - - if isinstance(value, (AccountRole, AccountStatus)): - update_values[field] = value.value - else: - update_values[field] = value - - for field, new_value in update_values.items(): - if not hasattr(user, field): - continue - - current_value = getattr(user, field) - - if isinstance(current_value, Enum): - current_value = current_value.value - - if current_value != new_value: - changes[field] = new_value - - return changes if changes else None - - -def update_key_data_changes(update_data: AccountKeyringUpdate, key) -> Optional[dict]: - """ - Сравнивает данные для обновления с текущими значениями пользователя. - Возвращает: - - None, если нет изменений - - Словарь {поле: новое_значение} для измененных полей - """ - update_values = {} - changes = {} - - for field, value in update_data.model_dump(exclude_unset=True).items(): - if value is None: - continue - - if isinstance(value, (KeyType, KeyStatus)): - update_values[field] = value.value - else: - update_values[field] = value - - for field, new_value in update_values.items(): - if not hasattr(key, field): - continue - - current_value = getattr(key, field) - - if isinstance(current_value, Enum): - current_value = current_value.value - - if current_value != new_value: - changes[field] = new_value - - return changes if changes else None - - -def update_listevents_data_changes(update_data: ListEventUpdate, listevents) -> Optional[dict]: - """ - Сравнивает данные для обновления с текущими значениями listevents. - Возвращает: - - None, если нет изменений - - Словарь {поле: новое_значение} для измененных полей - """ - update_values = {} - changes = {} - - for field, value in update_data.model_dump(exclude_unset=True).items(): - if value is None: - continue - - if isinstance(value, (EventState, EventStatus)): - update_values[field] = value.value - else: - update_values[field] = value - - for field, new_value in update_values.items(): - if not hasattr(listevents, field): - continue - - current_value = getattr(listevents, field) - - if isinstance(current_value, Enum): - current_value = current_value.value - - if current_value != new_value: - changes[field] = new_value - - return changes if changes else None - - -def update_processschema_data_changes(update_data: ProcessSchemaUpdate, processschema) -> Optional[dict]: - """ - Сравнивает данные для обновления с текущими значениями processschema. - Возвращает: - - None, если нет изменений - - Словарь {поле: новое_значение} для измененных полей - """ - update_values = {} - changes = {} - - for field, value in update_data.model_dump(exclude_unset=True).items(): - if value is None: - continue - - if isinstance(value, (ProcessStatus)): - update_values[field] = value.value - else: - update_values[field] = value - - for field, new_value in update_values.items(): - if not hasattr(processschema, field): - continue - - current_value = getattr(processschema, field) - - if isinstance(current_value, Enum): - current_value = current_value.value - - if current_value != new_value: - changes[field] = new_value - - return changes if changes else None From c66c21eb14f1ecc09e0dc8c2e8fcd99dcb413568 Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Sat, 2 Aug 2025 21:42:06 +0500 Subject: [PATCH 14/16] feat:dto accaunt endpoint, dto list events endpoint --- api/api/db/logic/account.py | 104 ++++++++++++++---- api/api/db/logic/listevents.py | 113 +++++++++++++++++++- api/api/db/logic/processschema.py | 38 ++++--- api/api/endpoints/account.py | 42 +++++--- api/api/endpoints/listevents.py | 56 ++++++---- api/api/endpoints/processschema.py | 24 ++--- api/api/schemas/endpoints/account.py | 11 +- api/api/schemas/endpoints/list_events.py | 12 +++ api/api/schemas/endpoints/process_schema.py | 7 +- 9 files changed, 309 insertions(+), 98 deletions(-) diff --git a/api/api/db/logic/account.py b/api/api/db/logic/account.py index f6b92fb..039b9ca 100644 --- a/api/api/db/logic/account.py +++ b/api/api/db/logic/account.py @@ -3,44 +3,108 @@ from datetime import datetime, timezone from enum import Enum from typing import Optional -from sqlalchemy import func, insert, select +from sqlalchemy import insert, select, func, or_, and_, asc, desc from sqlalchemy.ext.asyncio import AsyncConnection from api.db.tables.account import account_table from api.schemas.account.account import User -from api.schemas.endpoints.account import all_user_adapter, AllUser, AllUserResponse, UserCreate +from api.schemas.endpoints.account import all_user_adapter, AllUser, AllUserResponse, UserCreate, UserFilterDTO -async def get_user_accaunt_page(connection: AsyncConnection, page, limit) -> Optional[AllUserResponse]: +async def get_user_account_page_DTO( + connection: AsyncConnection, filter_dto: UserFilterDTO +) -> Optional[AllUserResponse]: """ - Получает список ползовелей заданных значениями page, limit. + Получает список пользователей с пагинацией, фильтрацией и сортировкой через DTO объект. + Поддерживает: + - пагинацию + - поиск + - фильтрацию по полям + - сортировку """ - first_user = page * limit - (limit) + page = filter_dto.pagination.get("page", 1) + limit = filter_dto.pagination.get("limit", 10) + offset = (page - 1) * limit - query = ( - select( - account_table.c.id, - account_table.c.name, - account_table.c.login, - account_table.c.email, - account_table.c.bind_tenant_id, - account_table.c.role, - account_table.c.created_at, - account_table.c.status, - ) - .order_by(account_table.c.id) - .offset(first_user) - .limit(limit) + query = select( + account_table.c.id, + account_table.c.name, + account_table.c.login, + account_table.c.email, + account_table.c.bind_tenant_id, + account_table.c.role, + account_table.c.meta, + account_table.c.creator_id, + account_table.c.created_at, + account_table.c.status, ) + # Поиск + if filter_dto.search: + search_term = f"%{filter_dto.search}%" + query = query.where( + or_( + account_table.c.name.ilike(search_term), + account_table.c.login.ilike(search_term), + account_table.c.email.ilike(search_term), + ) + ) + + # Фильтрацию + filter_conditions = [] + if filter_dto.filters: + for field, values in filter_dto.filters.items(): + column = getattr(account_table.c, field, None) + if column is not None and values: + if len(values) == 1: + filter_conditions.append(column == values[0]) + else: + filter_conditions.append(column.in_(values)) + + if filter_conditions: + query = query.where(and_(*filter_conditions)) + + # Сортировка + if filter_dto.order: + order_field = filter_dto.order.get("field", "id") + order_direction = filter_dto.order.get("direction", "asc") + + column = getattr(account_table.c, order_field, None) + if column is not None: + if order_direction.lower() == "desc": + query = query.order_by(desc(column)) + else: + query = query.order_by(asc(column)) + else: + query = query.order_by(account_table.c.id) + + query = query.offset(offset).limit(limit) + count_query = select(func.count()).select_from(account_table) + if filter_dto.search: + search_term = f"%{filter_dto.search}%" + count_query = count_query.where( + or_( + account_table.c.name.ilike(search_term), + account_table.c.login.ilike(search_term), + account_table.c.email.ilike(search_term), + ) + ) + + if filter_conditions: + count_query = count_query.where(and_(*filter_conditions)) + result = await connection.execute(query) count_result = await connection.execute(count_query) users_data = result.mappings().all() total_count = count_result.scalar() + + if not total_count: + return None + total_pages = math.ceil(total_count / limit) validated_users = all_user_adapter.validate_python(users_data) @@ -66,7 +130,7 @@ async def get_user_by_id(connection: AsyncConnection, user_id: int) -> Optional[ if not user: return None - return AllUser.model_validate(user) + return User.model_validate(user) async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional[User]: diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/listevents.py index d00818b..505dc7e 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/listevents.py @@ -3,17 +3,122 @@ import math from datetime import datetime, timezone -from sqlalchemy import insert, select, func + +from sqlalchemy import insert, select, func, or_, and_, asc, desc from sqlalchemy.ext.asyncio import AsyncConnection -from enum import Enum from api.db.tables.events import list_events_table - from api.schemas.events.list_events import ListEvent +from api.schemas.endpoints.list_events import all_list_event_adapter, AllListEventResponse, ListEventFilterDTO -from api.schemas.endpoints.list_events import all_list_event_adapter, AllListEventResponse + +async def get_listevents_page_DTO( + connection: AsyncConnection, filter_dto: ListEventFilterDTO +) -> Optional[AllListEventResponse]: + """ + Получает список событий с фильтрацией через DTO объект. + Поддерживает: + - пагинацию + - полнотекстовый поиск (пропускает name при русских буквах) + - фильтрацию по полям + - сортировку + """ + page = filter_dto.pagination.get("page", 1) + limit = filter_dto.pagination.get("limit", 10) + offset = (page - 1) * limit + + query = select( + list_events_table.c.id, + list_events_table.c.name, + list_events_table.c.title, + list_events_table.c.creator_id, + list_events_table.c.created_at, + list_events_table.c.schema.label("schema_"), + list_events_table.c.state, + list_events_table.c.status, + ) + + if filter_dto.search: + search_term = f"%{filter_dto.search}%" + has_russian = any("\u0400" <= char <= "\u04ff" for char in filter_dto.search) + + if has_russian: + query = query.where(list_events_table.c.title.ilike(search_term)) + else: + query = query.where( + or_(list_events_table.c.title.ilike(search_term), list_events_table.c.name.ilike(search_term)) + ) + + filter_conditions = [] + if filter_dto.filters: + for field, values in filter_dto.filters.items(): + column = getattr(list_events_table.c, field, None) + if column is not None and values: + if len(values) == 1: + filter_conditions.append(column == values[0]) + else: + filter_conditions.append(column.in_(values)) + + if filter_conditions: + query = query.where(and_(*filter_conditions)) + + if filter_dto.order: + order_field = filter_dto.order.get("field", "id") + order_direction = filter_dto.order.get("direction", "asc") + + if order_field.startswith("schema."): + json_field = order_field[7:] + column = list_events_table.c.schema[json_field].astext + else: + column = getattr(list_events_table.c, order_field, None) + + if column is not None: + if order_direction.lower() == "desc": + query = query.order_by(desc(column)) + else: + query = query.order_by(asc(column)) + else: + query = query.order_by(list_events_table.c.id) + + query = query.offset(offset).limit(limit) + + count_query = select(func.count()).select_from(list_events_table) + + if filter_dto.search: + search_term = f"%{filter_dto.search}%" + has_russian = any("\u0400" <= char <= "\u04ff" for char in filter_dto.search) + + if has_russian: + count_query = count_query.where(list_events_table.c.title.ilike(search_term)) + else: + count_query = count_query.where( + or_(list_events_table.c.title.ilike(search_term), list_events_table.c.name.ilike(search_term)) + ) + + if filter_conditions: + count_query = count_query.where(and_(*filter_conditions)) + + result = await connection.execute(query) + count_result = await connection.execute(count_query) + + events_data = result.mappings().all() + total_count = count_result.scalar() + + if not total_count: + return None + + total_pages = math.ceil(total_count / limit) + validated_events = all_list_event_adapter.validate_python(events_data) + + return AllListEventResponse( + list_event=validated_events, + amount_count=total_count, + amount_pages=total_pages, + current_page=page, + limit=limit, + ) async def get_listevents_page_by_creator_id( diff --git a/api/api/db/logic/processschema.py b/api/api/db/logic/processschema.py index 21c3763..f737432 100644 --- a/api/api/db/logic/processschema.py +++ b/api/api/db/logic/processschema.py @@ -3,23 +3,34 @@ import math from datetime import datetime, timezone -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 api.db.tables.process import process_schema_table from api.schemas.process.process_schema import ProcessSchema -from api.schemas.endpoints.process_schema import all_process_schema_adapter, AllProcessSchemaResponse, ProcessSchemaFilterDTO +from api.schemas.endpoints.process_schema import ( + all_process_schema_adapter, + AllProcessSchemaResponse, + ProcessSchemaFilterDTO, +) -async def get_process_schema_page(connection: AsyncConnection, filter_dto: ProcessSchemaFilterDTO) -> Optional[AllProcessSchemaResponse]: +async def get_process_schema_page_DTO( + connection: AsyncConnection, filter_dto: ProcessSchemaFilterDTO +) -> Optional[AllProcessSchemaResponse]: """ Получает список схем процессов с комплексной фильтрацией через DTO объект. + Поддерживает: + - пагинацию + - поиск + - фильтрацию по полям + - сортировку """ - page = filter_dto.pagination.get('page', 1) - limit = filter_dto.pagination.get('limit', 10) + page = filter_dto.pagination.get("page", 1) + limit = filter_dto.pagination.get("limit", 10) offset = (page - 1) * limit query = select( @@ -36,10 +47,7 @@ async def get_process_schema_page(connection: AsyncConnection, filter_dto: Proce if filter_dto.search: search_term = f"%{filter_dto.search}%" query = query.where( - or_( - process_schema_table.c.title.ilike(search_term), - process_schema_table.c.description.ilike(search_term) - ) + or_(process_schema_table.c.title.ilike(search_term), process_schema_table.c.description.ilike(search_term)) ) if filter_dto.filters: @@ -56,12 +64,12 @@ async def get_process_schema_page(connection: AsyncConnection, filter_dto: Proce query = query.where(and_(*filter_conditions)) if filter_dto.order: - order_field = filter_dto.order.get('field', 'id') - order_direction = filter_dto.order.get('direction', 'asc') + order_field = filter_dto.order.get("field", "id") + order_direction = filter_dto.order.get("direction", "asc") column = getattr(process_schema_table.c, order_field, None) if column is not None: - if order_direction.lower() == 'desc': + if order_direction.lower() == "desc": query = query.order_by(desc(column)) else: query = query.order_by(asc(column)) @@ -75,10 +83,7 @@ async def get_process_schema_page(connection: AsyncConnection, filter_dto: Proce if filter_dto.search: search_term = f"%{filter_dto.search}%" count_query = count_query.where( - or_( - process_schema_table.c.title.ilike(search_term), - process_schema_table.c.description.ilike(search_term) - ) + or_(process_schema_table.c.title.ilike(search_term), process_schema_table.c.description.ilike(search_term)) ) if filter_dto.filters and filter_conditions: @@ -105,6 +110,7 @@ async def get_process_schema_page(connection: AsyncConnection, filter_dto: Proce limit=limit, ) + async def get_process_schema_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]: """ Получает process schema по title. diff --git a/api/api/endpoints/account.py b/api/api/endpoints/account.py index a66b683..7506314 100644 --- a/api/api/endpoints/account.py +++ b/api/api/endpoints/account.py @@ -1,15 +1,12 @@ -from fastapi import ( - APIRouter, - Depends, - HTTPException, - status, -) +from fastapi import APIRouter, Depends, HTTPException, status, Query + +from typing import Optional, List from sqlalchemy.ext.asyncio import AsyncConnection from api.db.connection.session import get_connection_dep from api.db.logic.account import ( create_user, - get_user_accaunt_page, + get_user_account_page_DTO, get_user_by_id, get_user_by_login, update_user_by_id, @@ -18,7 +15,7 @@ from api.db.logic.keyring import create_password_key, update_password_key from api.db.tables.account import AccountStatus from api.schemas.account.account import User from api.schemas.base import bearer_schema -from api.schemas.endpoints.account import AllUser, AllUserResponse, UserCreate, UserUpdate +from api.schemas.endpoints.account import AllUserResponse, UserCreate, UserUpdate, UserFilterDTO from api.services.auth import get_current_user from api.services.user_role_validation import db_user_role_validation @@ -30,14 +27,33 @@ api_router = APIRouter( @api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllUserResponse) async def get_all_account( - page: int = 1, - limit: int = 10, + page: int = Query(1, description="Page number", gt=0), + limit: int = Query(10, description="КNumber of items per page", gt=0), + search: Optional[str] = Query(None, description="Search term to filter by name or login or email"), + status_filter: Optional[List[str]] = Query(None, description="Filter by status"), + role_filter: Optional[List[str]] = Query(None, description="Filter by role"), + creator_id: Optional[int] = Query(None, description="Filter by creator id"), + order_field: Optional[str] = Query("id", description="Field to sort by"), + order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): authorize_user = await db_user_role_validation(connection, current_user) - user_list = await get_user_accaunt_page(connection, page, limit) + filters = { + **({"status": status_filter} if status_filter else {}), + **({"role": role_filter} if role_filter else {}), + **({"creator_id": [str(creator_id)]} if creator_id else {}), + } + + filter_dto = UserFilterDTO( + pagination={"page": page, "limit": limit}, + search=search, + order={"field": order_field, "direction": order_direction}, + filters=filters if filters else None, + ) + + user_list = await get_user_account_page_DTO(connection, filter_dto) if user_list is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Accounts not found") @@ -45,7 +61,7 @@ async def get_all_account( return user_list -@api_router.get("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=UserUpdate) +@api_router.get("/{user_id}", dependencies=[Depends(bearer_schema)], response_model=User) async def get_account( user_id: int, connection: AsyncConnection = Depends(get_connection_dep), @@ -61,7 +77,7 @@ async def get_account( return user -@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=AllUser) +@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=User) async def create_account( user: UserCreate, connection: AsyncConnection = Depends(get_connection_dep), diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/listevents.py index 33bb4ec..b87fc0e 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/listevents.py @@ -1,10 +1,6 @@ -from fastapi import ( - APIRouter, - Depends, - HTTPException, - status, -) +from fastapi import APIRouter, Depends, HTTPException, status, Query +from typing import Optional, List from sqlalchemy.ext.asyncio import AsyncConnection @@ -17,8 +13,7 @@ from api.db.logic.listevents import ( get_listevents_by_id, create_listevents, update_listevents_by_id, - get_listevents_page, - get_listevents_page_by_creator_id, + get_listevents_page_DTO, ) @@ -27,7 +22,7 @@ from api.db.tables.events import EventStatus from api.schemas.base import bearer_schema -from api.schemas.endpoints.list_events import ListEventUpdate, AllListEventResponse +from api.schemas.endpoints.list_events import ListEventUpdate, AllListEventResponse, ListEventFilterDTO from api.services.auth import get_current_user @@ -37,7 +32,6 @@ from api.services.user_role_validation import ( ) - api_router = APIRouter( prefix="/listevents", tags=["list events"], @@ -46,27 +40,43 @@ api_router = APIRouter( @api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllListEventResponse) async def get_all_list_events( - page: int = 1, - limit: int = 10, + page: int = Query(1, description="Page number", gt=0), + limit: int = Query(10, description="Number of items per page", gt=0), + search: Optional[str] = Query(None, description="Search term to filter by title or name"), + order_field: Optional[str] = Query("id", description="Field to sort by"), + order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), + status_filter: Optional[List[str]] = Query(None, description="Filter by status"), + state_filter: Optional[List[str]] = Query(None, description="Filter by state"), + creator_id: Optional[int] = Query(None, description="Filter by creator id"), connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): + filters = { + **({"status": status_filter} if status_filter else {}), + **({"creator_id": [str(creator_id)]} if creator_id else {}), + **({"state": state_filter} if state_filter else {}), + } + + filter_dto = ListEventFilterDTO( + pagination={"page": page, "limit": limit}, + search=search, + order={"field": order_field, "direction": order_direction}, + filters=filters if filters else None, + ) + authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) - if page_flag: - list_events_page = await get_listevents_page(connection, page, limit) + if not page_flag: + if filter_dto.filters is None: + filter_dto.filters = {} + filter_dto.filters["creator_id"] = [str(authorize_user.id)] - if list_events_page is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") + list_events_page = await get_listevents_page_DTO(connection, filter_dto) - return list_events_page - else: - list_events_page = await get_listevents_page_by_creator_id(connection, authorize_user.id, page, limit) + if list_events_page is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - if list_events_page is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - - return list_events_page + return list_events_page @api_router.get("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/processschema.py index 5be73a9..b7e5522 100644 --- a/api/api/endpoints/processschema.py +++ b/api/api/endpoints/processschema.py @@ -1,10 +1,4 @@ -from fastapi import ( - APIRouter, - Depends, - HTTPException, - status, - Query -) +from fastapi import APIRouter, Depends, HTTPException, status, Query from typing import Optional, Dict, Any, List from sqlalchemy.ext.asyncio import AsyncConnection @@ -18,7 +12,7 @@ from api.db.logic.processschema import ( create_process_schema, get_process_schema_by_id, update_process_schema_by_id, - get_process_schema_page, + get_process_schema_page_DTO, ) from api.schemas.process.process_schema import ProcessSchema @@ -51,12 +45,11 @@ async def get_all_process_schema( order_field: Optional[str] = Query("id", description="Field to sort by"), order_direction: Optional[str] = Query("asc", description="Sort direction (asc/desc)"), status_filter: Optional[List[str]] = Query(None, description="Filter by status"), - owner_id: Optional[List[str]] = Query(None, description="Filter by owner ID"), + owner_id: Optional[List[str]] = Query(None, description="Filter by owner id"), connection: AsyncConnection = Depends(get_connection_dep), - creator_id: Optional[int] = Query(None, description="Filter by creator ID"), + creator_id: Optional[int] = Query(None, description="Filter by creator id"), current_user=Depends(get_current_user), ): - filters = { **({"status": status_filter} if status_filter else {}), **({"owner_id": owner_id} if owner_id else {}), @@ -67,7 +60,7 @@ async def get_all_process_schema( pagination={"page": page, "limit": limit}, search=search, order={"field": order_field, "direction": order_direction}, - filters=filters if filters else None + filters=filters if filters else None, ) authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) @@ -77,13 +70,10 @@ async def get_all_process_schema( filter_dto.filters = {} filter_dto.filters["creator_id"] = [str(authorize_user.id)] - process_schema_page = await get_process_schema_page(connection, filter_dto) + process_schema_page = await get_process_schema_page_DTO(connection, filter_dto) if process_schema_page is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Process schema not found" - ) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") return process_schema_page diff --git a/api/api/schemas/endpoints/account.py b/api/api/schemas/endpoints/account.py index 0aa0c84..9fa15c2 100644 --- a/api/api/schemas/endpoints/account.py +++ b/api/api/schemas/endpoints/account.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Optional +from typing import List, Optional, Dict from pydantic import EmailStr, Field, TypeAdapter @@ -36,6 +36,8 @@ class AllUser(Base): email: Optional[EmailStr] = None bind_tenant_id: Optional[str] = None role: AccountRole + meta: Optional[dict] = None + creator_id: Optional[int] = None created_at: datetime status: AccountStatus @@ -49,3 +51,10 @@ class AllUserResponse(Base): all_user_adapter = TypeAdapter(List[AllUser]) + + +class UserFilterDTO(Base): + pagination: Dict[str, int] + search: Optional[str] = None + order: Optional[Dict[str, str]] = None + filters: Optional[Dict[str, List[str]]] = None diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index c0f99bf..75a9e79 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -35,3 +35,15 @@ class AllListEventResponse(Base): all_list_event_adapter = TypeAdapter(List[AllListEvent]) + + +class ListEventFilterDTO(Base): + pagination: Dict[str, int] = Field( + default={"page": 1, "limit": 10}, + description="Пагинация (номер страницы и количество элементов)", + ) + search: Optional[str] = Field(default=None, description="Поиск по текстовым полям (name, title)") + order: Optional[Dict[str, str]] = Field( + default={"field": "id", "direction": "asc"}, description="Сортировка (поле и направление)" + ) + filters: Optional[Dict[str, List[str]]] = Field(default=None, description="Фильтрация по точным значениям") diff --git a/api/api/schemas/endpoints/process_schema.py b/api/api/schemas/endpoints/process_schema.py index f00b5df..acafea8 100644 --- a/api/api/schemas/endpoints/process_schema.py +++ b/api/api/schemas/endpoints/process_schema.py @@ -37,9 +37,8 @@ class AllProcessSchemaResponse(Base): all_process_schema_adapter = TypeAdapter(List[AllProcessSchema]) -# DTO объект для фильтрации class ProcessSchemaFilterDTO(Base): - pagination: Dict[str, int] # {page: 1, limit: 10} + pagination: Dict[str, int] search: Optional[str] = None - order: Optional[Dict[str, str]] = None # {field: "id", direction: "asc"} - filters: Optional[Dict[str, List[str]]] = None # {"status": ["active"], "owner_id": ["123"]} + order: Optional[Dict[str, str]] = None + filters: Optional[Dict[str, List[str]]] = None From 3c300f7c7aeb33e555afb8fde0de5b99b7cdf686 Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Sat, 2 Aug 2025 22:05:29 +0500 Subject: [PATCH 15/16] fix: rename process schema --- .../{processschema.py => process_schema.py} | 36 ++++----- api/api/endpoints/__init__.py | 2 +- .../{processschema.py => process_schema.py} | 76 +++++++++---------- api/api/schemas/endpoints/list_events.py | 13 +--- 4 files changed, 61 insertions(+), 66 deletions(-) rename api/api/db/logic/{processschema.py => process_schema.py} (84%) rename api/api/endpoints/{processschema.py => process_schema.py} (67%) diff --git a/api/api/db/logic/processschema.py b/api/api/db/logic/process_schema.py similarity index 84% rename from api/api/db/logic/processschema.py rename to api/api/db/logic/process_schema.py index f737432..907be98 100644 --- a/api/api/db/logic/processschema.py +++ b/api/api/db/logic/process_schema.py @@ -117,59 +117,59 @@ async def get_process_schema_by_title(connection: AsyncConnection, title: str) - """ query = select(process_schema_table).where(process_schema_table.c.title == title) - processschema_db_cursor = await connection.execute(query) + process_schema_db_cursor = await connection.execute(query) - processschema_data = processschema_db_cursor.mappings().one_or_none() - if not processschema_data: + process_schema_data = process_schema_db_cursor.mappings().one_or_none() + if not process_schema_data: return None - return ProcessSchema.model_validate(processschema_data) + return ProcessSchema.model_validate(process_schema_data) async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]: """ - Получает processschema по id. + Получает process_schema по id. """ query = select(process_schema_table).where(process_schema_table.c.id == id) - processschema_db_cursor = await connection.execute(query) + process_schema_db_cursor = await connection.execute(query) - processschema_data = processschema_db_cursor.mappings().one_or_none() - if not processschema_data: + process_schema_data = process_schema_db_cursor.mappings().one_or_none() + if not process_schema_data: return None - return ProcessSchema.model_validate(processschema_data) + return ProcessSchema.model_validate(process_schema_data) -async def update_process_schema_by_id(connection: AsyncConnection, update_values, processschema): +async def update_process_schema_by_id(connection: AsyncConnection, update_values, process_schema): """ Вносит изменеия в нужное поле таблицы process_schema_table. """ await connection.execute( - process_schema_table.update().where(process_schema_table.c.id == processschema.id).values(**update_values) + process_schema_table.update().where(process_schema_table.c.id == process_schema.id).values(**update_values) ) await connection.commit() async def create_process_schema( - connection: AsyncConnection, processschema: ProcessSchema, creator_id: int + connection: AsyncConnection, process_schema: ProcessSchema, creator_id: int ) -> Optional[ProcessSchema]: """ Создает нове поле в таблице process_schema_table. """ query = insert(process_schema_table).values( - title=processschema.title, - description=processschema.description, - owner_id=processschema.owner_id, + 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=processschema.settings, - status=processschema.status.value, + settings=process_schema.settings, + status=process_schema.status.value, ) await connection.execute(query) await connection.commit() - return processschema + return process_schema diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index be25e82..f131470 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -3,7 +3,7 @@ from api.endpoints.profile import api_router as profile_router from api.endpoints.account import api_router as account_router from api.endpoints.keyring import api_router as keyring_router from api.endpoints.listevents import api_router as listevents_router -from api.endpoints.processschema import api_router as processschema_router +from api.endpoints.process_schema import api_router as processschema_router list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router, processschema_router] diff --git a/api/api/endpoints/processschema.py b/api/api/endpoints/process_schema.py similarity index 67% rename from api/api/endpoints/processschema.py rename to api/api/endpoints/process_schema.py index b7e5522..b5e1f81 100644 --- a/api/api/endpoints/processschema.py +++ b/api/api/endpoints/process_schema.py @@ -1,13 +1,13 @@ from fastapi import APIRouter, Depends, HTTPException, status, Query -from typing import Optional, Dict, Any, List +from typing import Optional, List 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.db.logic.processschema import ( +from api.db.logic.process_schema import ( get_process_schema_by_title, create_process_schema, get_process_schema_by_id, @@ -32,7 +32,7 @@ from api.services.user_role_validation import ( api_router = APIRouter( - prefix="/process-schema", + prefix="/process_schema", tags=["process schema"], ) @@ -78,40 +78,40 @@ async def get_all_process_schema( return process_schema_page -@api_router.get("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +@api_router.get("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) async def get_process_schema( - processschema_id: int, + process_schema_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - processschema_validation = await get_process_schema_by_id(connection, processschema_id) + process_schema_validation = await get_process_schema_by_id(connection, process_schema_id) - if processschema_validation is None: + if process_schema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( - connection, current_user, processschema_validation.creator_id + connection, current_user, process_schema_validation.creator_id ) - if processschema_id is None: + if process_schema_id is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") - return processschema_validation + return process_schema_validation @api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) async def create_processschema( - processschema: ProcessSchemaUpdate, + process_schema: ProcessSchemaUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): user_validation = await get_user_by_login(connection, current_user) - processschema_validation = await get_process_schema_by_title(connection, processschema.title) + process_schema_validation = await get_process_schema_by_title(connection, process_schema.title) - if processschema_validation is None: - await create_process_schema(connection, processschema, user_validation.id) - processschema_new = await get_process_schema_by_title(connection, processschema.title) - return processschema_new + 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 else: raise HTTPException( @@ -119,58 +119,58 @@ async def create_processschema( ) -@api_router.put("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +@api_router.put("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) async def update_process_schema( - processschema_id: int, - processschema_update: ProcessSchemaUpdate, + process_schema_id: int, + process_schema_update: ProcessSchemaUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - processschema_validation = await get_process_schema_by_id(connection, processschema_id) + process_schema_validation = await get_process_schema_by_id(connection, process_schema_id) - if processschema_validation is None: + if process_schema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( - connection, current_user, processschema_validation.creator_id + connection, current_user, process_schema_validation.creator_id ) - updated_values = processschema_update.model_dump(by_alias=True, exclude_none=True) + updated_values = process_schema_update.model_dump(by_alias=True, exclude_none=True) if not updated_values: - return processschema_validation + return process_schema_validation - await update_process_schema_by_id(connection, updated_values, processschema_validation) + await update_process_schema_by_id(connection, updated_values, process_schema_validation) - processschema = await get_process_schema_by_id(connection, processschema_id) + process_schema = await get_process_schema_by_id(connection, process_schema_id) - return processschema + return process_schema -@api_router.delete("/{processschema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) +@api_router.delete("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema) async def delete_process_schema( - processschema_id: int, + process_schema_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - processschema_validation = await get_process_schema_by_id(connection, processschema_id) + process_schema_validation = await get_process_schema_by_id(connection, process_schema_id) - if processschema_validation is None: + if process_schema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( - connection, current_user, processschema_validation.creator_id + connection, current_user, process_schema_validation.creator_id ) - processschema_update = ProcessSchemaUpdate(status=ProcessStatus.DELETED.value) + process_schema_update = ProcessSchemaUpdate(status=ProcessStatus.DELETED.value) - updated_values = processschema_update.model_dump(by_alias=True, exclude_none=True) + updated_values = process_schema_update.model_dump(by_alias=True, exclude_none=True) if not updated_values: - return processschema_validation + return process_schema_validation - await update_process_schema_by_id(connection, updated_values, processschema_validation) + await update_process_schema_by_id(connection, updated_values, process_schema_validation) - processschema = await get_process_schema_by_id(connection, processschema_id) + process_schema = await get_process_schema_by_id(connection, process_schema_id) - return processschema + return process_schema diff --git a/api/api/schemas/endpoints/list_events.py b/api/api/schemas/endpoints/list_events.py index 75a9e79..6f41a3e 100644 --- a/api/api/schemas/endpoints/list_events.py +++ b/api/api/schemas/endpoints/list_events.py @@ -38,12 +38,7 @@ all_list_event_adapter = TypeAdapter(List[AllListEvent]) class ListEventFilterDTO(Base): - pagination: Dict[str, int] = Field( - default={"page": 1, "limit": 10}, - description="Пагинация (номер страницы и количество элементов)", - ) - search: Optional[str] = Field(default=None, description="Поиск по текстовым полям (name, title)") - order: Optional[Dict[str, str]] = Field( - default={"field": "id", "direction": "asc"}, description="Сортировка (поле и направление)" - ) - filters: Optional[Dict[str, List[str]]] = Field(default=None, description="Фильтрация по точным значениям") + pagination: Dict[str, int] + search: Optional[str] = None + order: Optional[Dict[str, str]] = None + filters: Optional[Dict[str, List[str]]] = None From d9e88d66f7071ea2b5a0a4c5007ffe991004b403 Mon Sep 17 00:00:00 2001 From: TheNoxium Date: Mon, 4 Aug 2025 16:15:35 +0500 Subject: [PATCH 16/16] fix: rename list events --- .../logic/{listevents.py => list_events.py} | 46 ++++---- api/api/endpoints/__init__.py | 2 +- .../{listevents.py => list_events.py} | 102 +++++++++--------- api/api/endpoints/process_schema.py | 14 +-- api/api/services/user_role_validation.py | 4 +- 5 files changed, 87 insertions(+), 81 deletions(-) rename api/api/db/logic/{listevents.py => list_events.py} (85%) rename api/api/endpoints/{listevents.py => list_events.py} (57%) diff --git a/api/api/db/logic/listevents.py b/api/api/db/logic/list_events.py similarity index 85% rename from api/api/db/logic/listevents.py rename to api/api/db/logic/list_events.py index 505dc7e..f1cfd4b 100644 --- a/api/api/db/logic/listevents.py +++ b/api/api/db/logic/list_events.py @@ -14,7 +14,7 @@ from api.schemas.events.list_events import ListEvent from api.schemas.endpoints.list_events import all_list_event_adapter, AllListEventResponse, ListEventFilterDTO -async def get_listevents_page_DTO( +async def get_list_events_page_DTO( connection: AsyncConnection, filter_dto: ListEventFilterDTO ) -> Optional[AllListEventResponse]: """ @@ -121,7 +121,7 @@ async def get_listevents_page_DTO( ) -async def get_listevents_page_by_creator_id( +async def get_list_events_page_by_creator_id( connection: AsyncConnection, creator_id: int, page: int, limit: int ) -> Optional[AllListEventResponse]: """ @@ -171,7 +171,7 @@ async def get_listevents_page_by_creator_id( ) -async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]: +async def get_list_events_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]: """ Получает список событий заданного создателя по значениям page и limit. """ @@ -215,63 +215,65 @@ async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optio ) -async def get_listevents_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: +async def get_list_events_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]: """ Получает list events по name. """ query = select(list_events_table).where(list_events_table.c.name == name) - listevents_db_cursor = await connection.execute(query) + list_events_db_cursor = await connection.execute(query) - listevents_data = listevents_db_cursor.mappings().one_or_none() - if not listevents_data: + list_events_data = list_events_db_cursor.mappings().one_or_none() + if not list_events_data: return None - return ListEvent.model_validate(listevents_data) + return ListEvent.model_validate(list_events_data) -async def get_listevents_by_id(connection: AsyncConnection, id: int) -> Optional[ListEvent]: +async def get_list_events_by_id(connection: AsyncConnection, id: int) -> Optional[ListEvent]: """ Получает listevent по id. """ query = select(list_events_table).where(list_events_table.c.id == id) - listevents_db_cursor = await connection.execute(query) + list_events_db_cursor = await connection.execute(query) - listevents_data = listevents_db_cursor.mappings().one_or_none() - if not listevents_data: + list_events_data = list_events_db_cursor.mappings().one_or_none() + if not list_events_data: return None - return ListEvent.model_validate(listevents_data) + return ListEvent.model_validate(list_events_data) -async def update_listevents_by_id(connection: AsyncConnection, update_values, listevents): +async def update_list_events_by_id(connection: AsyncConnection, update_values, list_events): """ Вносит изменеия в нужное поле таблицы list_events_table. """ await connection.execute( - list_events_table.update().where(list_events_table.c.id == listevents.id).values(**update_values) + list_events_table.update().where(list_events_table.c.id == list_events.id).values(**update_values) ) await connection.commit() -async def create_listevents(connection: AsyncConnection, listevents: ListEvent, creator_id: int) -> Optional[ListEvent]: +async def create_list_events( + connection: AsyncConnection, list_events: ListEvent, creator_id: int +) -> Optional[ListEvent]: """ Создает нове поле в таблице list_events_table. """ query = insert(list_events_table).values( - name=listevents.name, - title=listevents.title, # добавлено поле title + name=list_events.name, + title=list_events.title, # добавлено поле title creator_id=creator_id, created_at=datetime.now(timezone.utc), - schema=listevents.schema_, # добавлено поле schema - state=listevents.state.value, # добавлено поле state - status=listevents.status.value, # добавлено поле status + schema=list_events.schema_, # добавлено поле schema + state=list_events.state.value, # добавлено поле state + status=list_events.status.value, # добавлено поле status ) await connection.execute(query) await connection.commit() - return listevents + return list_events diff --git a/api/api/endpoints/__init__.py b/api/api/endpoints/__init__.py index f131470..a67dff7 100644 --- a/api/api/endpoints/__init__.py +++ b/api/api/endpoints/__init__.py @@ -2,7 +2,7 @@ from api.endpoints.auth import api_router as auth_router from api.endpoints.profile import api_router as profile_router from api.endpoints.account import api_router as account_router from api.endpoints.keyring import api_router as keyring_router -from api.endpoints.listevents import api_router as listevents_router +from api.endpoints.list_events import api_router as listevents_router from api.endpoints.process_schema import api_router as processschema_router list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router, processschema_router] diff --git a/api/api/endpoints/listevents.py b/api/api/endpoints/list_events.py similarity index 57% rename from api/api/endpoints/listevents.py rename to api/api/endpoints/list_events.py index b87fc0e..b730af8 100644 --- a/api/api/endpoints/listevents.py +++ b/api/api/endpoints/list_events.py @@ -8,12 +8,12 @@ from api.db.connection.session import get_connection_dep from api.db.logic.account import get_user_by_login -from api.db.logic.listevents import ( - get_listevents_by_name, - get_listevents_by_id, - create_listevents, - update_listevents_by_id, - get_listevents_page_DTO, +from api.db.logic.list_events import ( + get_list_events_by_name, + get_list_events_by_id, + create_list_events, + update_list_events_by_id, + get_list_events_page_DTO, ) @@ -27,13 +27,13 @@ from api.schemas.endpoints.list_events import ListEventUpdate, AllListEventRespo from api.services.auth import get_current_user from api.services.user_role_validation import ( - db_user_role_validation_for_listevents_and_processschema_by_listevent_id, - db_user_role_validation_for_listevents_and_processschema, + db_user_role_validation_for_list_events_and_process_schema_by_list_event_id, + db_user_role_validation_for_list_events_and_process_schema, ) api_router = APIRouter( - prefix="/listevents", + prefix="/list_events", tags=["list events"], ) @@ -53,8 +53,8 @@ async def get_all_list_events( ): filters = { **({"status": status_filter} if status_filter else {}), - **({"creator_id": [str(creator_id)]} if creator_id else {}), **({"state": state_filter} if state_filter else {}), + **({"creator_id": [str(creator_id)]} if creator_id else {}), } filter_dto = ListEventFilterDTO( @@ -64,14 +64,16 @@ async def get_all_list_events( filters=filters if filters else None, ) - authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) + authorize_user, page_flag = await db_user_role_validation_for_list_events_and_process_schema( + connection, current_user + ) if not page_flag: if filter_dto.filters is None: filter_dto.filters = {} filter_dto.filters["creator_id"] = [str(authorize_user.id)] - list_events_page = await get_listevents_page_DTO(connection, filter_dto) + list_events_page = await get_list_events_page_DTO(connection, filter_dto) if list_events_page is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") @@ -79,40 +81,40 @@ async def get_all_list_events( return list_events_page -@api_router.get("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +@api_router.get("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) async def get_list_events( - listevents_id: int, + list_events_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - listevents_validation = await get_listevents_by_id(connection, listevents_id) + list_events_validation = await get_list_events_by_id(connection, list_events_id) - if listevents_validation is None: + if list_events_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( - connection, current_user, listevents_validation.creator_id + authorize_user = await db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( + connection, current_user, list_events_validation.creator_id ) - if listevents_id is None: + if list_events_id is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - return listevents_validation + return list_events_validation @api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ListEvent) async def create_list_events( - listevents: ListEventUpdate, + list_events: ListEventUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): user_validation = await get_user_by_login(connection, current_user) - listevents_validation = await get_listevents_by_name(connection, listevents.name) + list_events_validation = await get_list_events_by_name(connection, list_events.name) - if listevents_validation is None: - await create_listevents(connection, listevents, user_validation.id) - listevents_new = await get_listevents_by_name(connection, listevents.name) - return listevents_new + if list_events_validation is None: + await create_list_events(connection, list_events, user_validation.id) + list_events_new = await get_list_events_by_name(connection, list_events.name) + return list_events_new else: raise HTTPException( @@ -120,58 +122,58 @@ async def create_list_events( ) -@api_router.put("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +@api_router.put("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) async def update_list_events( - listevents_id: int, - listevents_update: ListEventUpdate, + list_events_id: int, + list_events_update: ListEventUpdate, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - listevents_validation = await get_listevents_by_id(connection, listevents_id) + list_events_validation = await get_list_events_by_id(connection, list_events_id) - if listevents_validation is None: + if list_events_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( - connection, current_user, listevents_validation.creator_id + authorize_user = await db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( + connection, current_user, list_events_validation.creator_id ) - updated_values = listevents_update.model_dump(by_alias=True, exclude_none=True) + updated_values = list_events_update.model_dump(by_alias=True, exclude_none=True) if not updated_values: - return listevents_validation + return list_events_validation - await update_listevents_by_id(connection, updated_values, listevents_validation) + await update_list_events_by_id(connection, updated_values, list_events_validation) - listevents = await get_listevents_by_id(connection, listevents_id) + list_events = await get_list_events_by_id(connection, list_events_id) - return listevents + return list_events -@api_router.delete("/{listevents_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) +@api_router.delete("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent) async def delete_list_events( - listevents_id: int, + list_events_id: int, connection: AsyncConnection = Depends(get_connection_dep), current_user=Depends(get_current_user), ): - listevents_validation = await get_listevents_by_id(connection, listevents_id) + list_events_validation = await get_list_events_by_id(connection, list_events_id) - if listevents_validation is None: + if list_events_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found") - authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( - connection, current_user, listevents_validation.creator_id + authorize_user = await db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( + connection, current_user, list_events_validation.creator_id ) - listevents_update = ListEventUpdate(status=EventStatus.DELETED.value) + list_events_update = ListEventUpdate(status=EventStatus.DELETED.value) - updated_values = listevents_update.model_dump(by_alias=True, exclude_none=True) + updated_values = list_events_update.model_dump(by_alias=True, exclude_none=True) if not updated_values: - return listevents_validation + return list_events_validation - await update_listevents_by_id(connection, updated_values, listevents_validation) + await update_list_events_by_id(connection, updated_values, list_events_validation) - listevents = await get_listevents_by_id(connection, listevents_id) + list_events = await get_list_events_by_id(connection, list_events_id) - return listevents + return list_events diff --git a/api/api/endpoints/process_schema.py b/api/api/endpoints/process_schema.py index b5e1f81..eee11b8 100644 --- a/api/api/endpoints/process_schema.py +++ b/api/api/endpoints/process_schema.py @@ -26,8 +26,8 @@ from api.schemas.endpoints.process_schema import ProcessSchemaUpdate, AllProcess from api.services.auth import get_current_user from api.services.user_role_validation import ( - db_user_role_validation_for_listevents_and_processschema_by_listevent_id, - db_user_role_validation_for_listevents_and_processschema, + db_user_role_validation_for_list_events_and_process_schema_by_list_event_id, + db_user_role_validation_for_list_events_and_process_schema, ) @@ -63,7 +63,9 @@ async def get_all_process_schema( filters=filters if filters else None, ) - authorize_user, page_flag = await db_user_role_validation_for_listevents_and_processschema(connection, current_user) + authorize_user, page_flag = await db_user_role_validation_for_list_events_and_process_schema( + connection, current_user + ) if not page_flag: if filter_dto.filters is None: @@ -89,7 +91,7 @@ async def get_process_schema( if process_schema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") - authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( + authorize_user = await db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( connection, current_user, process_schema_validation.creator_id ) @@ -131,7 +133,7 @@ async def update_process_schema( if process_schema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") - authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( + authorize_user = await db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( connection, current_user, process_schema_validation.creator_id ) @@ -158,7 +160,7 @@ async def delete_process_schema( if process_schema_validation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found") - authorize_user = await db_user_role_validation_for_listevents_and_processschema_by_listevent_id( + authorize_user = await db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( connection, current_user, process_schema_validation.creator_id ) diff --git a/api/api/services/user_role_validation.py b/api/api/services/user_role_validation.py index 657bd7e..1fc952d 100644 --- a/api/api/services/user_role_validation.py +++ b/api/api/services/user_role_validation.py @@ -13,7 +13,7 @@ async def db_user_role_validation(connection, current_user): return authorize_user -async def db_user_role_validation_for_listevents_and_processschema_by_listevent_id( +async def db_user_role_validation_for_list_events_and_process_schema_by_list_event_id( connection, current_user, current_listevents_creator_id ): authorize_user = await get_user_by_login(connection, current_user) @@ -23,7 +23,7 @@ async def db_user_role_validation_for_listevents_and_processschema_by_listevent_ return authorize_user -async def db_user_role_validation_for_listevents_and_processschema(connection, current_user): +async def db_user_role_validation_for_list_events_and_process_schema(connection, current_user): authorize_user = await get_user_by_login(connection, current_user) if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}: return authorize_user, False