Compare commits
14 Commits
VORKOUT-14
...
VORKOUT-19
Author | SHA1 | Date | |
---|---|---|---|
7fd0a732b3 | |||
571186151b | |||
1b95c9825b | |||
cf6e09d8c1 | |||
|
d9e88d66f7 | ||
|
3c300f7c7a | ||
|
c66c21eb14 | ||
|
a9ecaadad6 | ||
|
e50bb32470 | ||
|
2030d54b2c | ||
|
b82960faf3 | ||
|
e0887c240f | ||
5e3c3b4672 | |||
d03600b23d |
@@ -1,15 +1,15 @@
|
|||||||
import sys
|
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
import loguru
|
import loguru
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from uvicorn import run
|
from uvicorn import run
|
||||||
|
|
||||||
from api.config import get_settings, DefaultSettings
|
from api.config import DefaultSettings, get_settings
|
||||||
from api.endpoints import list_of_routes
|
from api.endpoints import list_of_routes
|
||||||
from api.utils.common import get_hostname
|
|
||||||
from api.services.middleware import MiddlewareAccessTokenValidadtion
|
from api.services.middleware import MiddlewareAccessTokenValidadtion
|
||||||
|
from api.utils.common import get_hostname
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
@@ -52,7 +52,6 @@ prod_origins = [""]
|
|||||||
|
|
||||||
origins = dev_origins if get_settings().ENV == "local" else prod_origins
|
origins = dev_origins if get_settings().ENV == "local" else prod_origins
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
settings_for_application = get_settings()
|
settings_for_application = get_settings()
|
||||||
if settings_for_application.ENV == "prod":
|
if settings_for_application.ENV == "prod":
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
from sqlalchemy import MetaData
|
|
||||||
|
|
||||||
metadata = MetaData()
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"metadata",
|
|
||||||
]
|
|
||||||
|
@@ -7,7 +7,7 @@ from sqlalchemy import pool
|
|||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
|
||||||
from api.db import metadata, tables
|
from orm import metadata, tables
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
|
@@ -3,44 +3,108 @@ from datetime import datetime, timezone
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional
|
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 sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
from api.db.tables.account import account_table
|
from orm.tables.account import account_table
|
||||||
from api.schemas.account.account import User
|
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 = (
|
query = select(
|
||||||
select(
|
account_table.c.id,
|
||||||
account_table.c.id,
|
account_table.c.name,
|
||||||
account_table.c.name,
|
account_table.c.login,
|
||||||
account_table.c.login,
|
account_table.c.email,
|
||||||
account_table.c.email,
|
account_table.c.bind_tenant_id,
|
||||||
account_table.c.bind_tenant_id,
|
account_table.c.role,
|
||||||
account_table.c.role,
|
account_table.c.meta,
|
||||||
account_table.c.created_at,
|
account_table.c.creator_id,
|
||||||
account_table.c.status,
|
account_table.c.created_at,
|
||||||
)
|
account_table.c.status,
|
||||||
.order_by(account_table.c.id)
|
|
||||||
.offset(first_user)
|
|
||||||
.limit(limit)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Поиск
|
||||||
|
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)
|
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)
|
result = await connection.execute(query)
|
||||||
count_result = await connection.execute(count_query)
|
count_result = await connection.execute(count_query)
|
||||||
|
|
||||||
users_data = result.mappings().all()
|
users_data = result.mappings().all()
|
||||||
total_count = count_result.scalar()
|
total_count = count_result.scalar()
|
||||||
|
|
||||||
|
if not total_count:
|
||||||
|
return None
|
||||||
|
|
||||||
total_pages = math.ceil(total_count / limit)
|
total_pages = math.ceil(total_count / limit)
|
||||||
|
|
||||||
validated_users = all_user_adapter.validate_python(users_data)
|
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:
|
if not user:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return AllUser.model_validate(user)
|
return User.model_validate(user)
|
||||||
|
|
||||||
|
|
||||||
async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional[User]:
|
async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional[User]:
|
||||||
@@ -76,20 +140,10 @@ async def get_user_by_login(connection: AsyncConnection, login: str) -> Optional
|
|||||||
query = select(account_table).where(account_table.c.login == login)
|
query = select(account_table).where(account_table.c.login == login)
|
||||||
|
|
||||||
user_db_cursor = await connection.execute(query)
|
user_db_cursor = await connection.execute(query)
|
||||||
user_db = user_db_cursor.one_or_none()
|
user_data = user_db_cursor.mappings().one_or_none()
|
||||||
|
if not user_data:
|
||||||
if not user_db:
|
|
||||||
return None
|
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)
|
return User.model_validate(user_data)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ from sqlalchemy import select, update
|
|||||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from api.db.tables.account import account_table, account_keyring_table, KeyType, KeyStatus
|
from orm.tables.account import account_table, account_keyring_table, KeyType, KeyStatus
|
||||||
|
|
||||||
from api.schemas.account.account import User
|
from api.schemas.account.account import User
|
||||||
from api.schemas.account.account_keyring import AccountKeyring
|
from api.schemas.account.account_keyring import AccountKeyring
|
||||||
|
@@ -6,7 +6,7 @@ from sqlalchemy import insert, select, update
|
|||||||
from sqlalchemy.dialects.mysql import insert as mysql_insert
|
from sqlalchemy.dialects.mysql import insert as mysql_insert
|
||||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
from api.db.tables.account import account_keyring_table, KeyStatus, KeyType
|
from orm.tables.account import account_keyring_table, KeyStatus, KeyType
|
||||||
from api.schemas.account.account_keyring import AccountKeyring
|
from api.schemas.account.account_keyring import AccountKeyring
|
||||||
from api.utils.hasher import hasher
|
from api.utils.hasher import hasher
|
||||||
|
|
||||||
@@ -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)
|
query = select(account_keyring_table).where(account_keyring_table.c.key_id == key_id)
|
||||||
|
|
||||||
user_db_cursor = await connection.execute(query)
|
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
|
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)
|
return AccountKeyring.model_validate(user_data)
|
||||||
|
|
||||||
|
|
||||||
|
279
api/api/db/logic/list_events.py
Normal file
279
api/api/db/logic/list_events.py
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
from typing import Optional
|
||||||
|
import math
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
from sqlalchemy import insert, select, func, or_, and_, asc, desc
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
|
from orm.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
|
||||||
|
|
||||||
|
|
||||||
|
async def get_list_events_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_list_events_page_by_creator_id(
|
||||||
|
connection: AsyncConnection, creator_id: int, page: int, limit: int
|
||||||
|
) -> Optional[AllListEventResponse]:
|
||||||
|
"""
|
||||||
|
Получает список событий заданного создателя по значениям page и limit и creator_id.
|
||||||
|
"""
|
||||||
|
|
||||||
|
first_event = page * limit - limit
|
||||||
|
query = (
|
||||||
|
select(
|
||||||
|
list_events_table.c.id,
|
||||||
|
list_events_table.c.name,
|
||||||
|
list_events_table.c.title,
|
||||||
|
list_events_table.c.creator_id,
|
||||||
|
list_events_table.c.created_at,
|
||||||
|
list_events_table.c.schema,
|
||||||
|
list_events_table.c.state,
|
||||||
|
list_events_table.c.status,
|
||||||
|
)
|
||||||
|
.where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id
|
||||||
|
.order_by(list_events_table.c.id)
|
||||||
|
.offset(first_event)
|
||||||
|
.limit(limit)
|
||||||
|
)
|
||||||
|
|
||||||
|
count_query = (
|
||||||
|
select(func.count())
|
||||||
|
.select_from(list_events_table)
|
||||||
|
.where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await connection.execute(query)
|
||||||
|
count_result = await connection.execute(count_query)
|
||||||
|
|
||||||
|
events_data = result.mappings().all()
|
||||||
|
total_count = count_result.scalar()
|
||||||
|
total_pages = math.ceil(total_count / limit)
|
||||||
|
|
||||||
|
# Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные
|
||||||
|
validated_list_event = all_list_event_adapter.validate_python(events_data)
|
||||||
|
|
||||||
|
return AllListEventResponse(
|
||||||
|
list_event=validated_list_event,
|
||||||
|
amount_count=total_count,
|
||||||
|
amount_pages=total_pages,
|
||||||
|
current_page=page,
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_list_events_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]:
|
||||||
|
"""
|
||||||
|
Получает список событий заданного создателя по значениям page и limit.
|
||||||
|
"""
|
||||||
|
|
||||||
|
first_event = page * limit - (limit)
|
||||||
|
|
||||||
|
query = (
|
||||||
|
select(
|
||||||
|
list_events_table.c.id,
|
||||||
|
list_events_table.c.name,
|
||||||
|
list_events_table.c.title,
|
||||||
|
list_events_table.c.creator_id,
|
||||||
|
list_events_table.c.created_at,
|
||||||
|
list_events_table.c.schema,
|
||||||
|
list_events_table.c.state,
|
||||||
|
list_events_table.c.status,
|
||||||
|
)
|
||||||
|
.order_by(list_events_table.c.id)
|
||||||
|
.offset(first_event)
|
||||||
|
.limit(limit)
|
||||||
|
)
|
||||||
|
|
||||||
|
count_query = select(func.count()).select_from(list_events_table)
|
||||||
|
|
||||||
|
result = await connection.execute(query)
|
||||||
|
count_result = await connection.execute(count_query)
|
||||||
|
|
||||||
|
events_data = result.mappings().all()
|
||||||
|
total_count = count_result.scalar()
|
||||||
|
total_pages = math.ceil(total_count / limit)
|
||||||
|
|
||||||
|
# Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные
|
||||||
|
validated_list_event = all_list_event_adapter.validate_python(events_data)
|
||||||
|
|
||||||
|
return AllListEventResponse(
|
||||||
|
list_event=validated_list_event,
|
||||||
|
amount_count=total_count,
|
||||||
|
amount_pages=total_pages,
|
||||||
|
current_page=page,
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_list_events_by_name(connection: AsyncConnection, name: str) -> Optional[ListEvent]:
|
||||||
|
"""
|
||||||
|
Получает list events по name.
|
||||||
|
"""
|
||||||
|
query = select(list_events_table).where(list_events_table.c.name == name)
|
||||||
|
|
||||||
|
list_events_db_cursor = await connection.execute(query)
|
||||||
|
|
||||||
|
list_events_data = list_events_db_cursor.mappings().one_or_none()
|
||||||
|
if not list_events_data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return ListEvent.model_validate(list_events_data)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
list_events_db_cursor = await connection.execute(query)
|
||||||
|
|
||||||
|
list_events_data = list_events_db_cursor.mappings().one_or_none()
|
||||||
|
if not list_events_data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return ListEvent.model_validate(list_events_data)
|
||||||
|
|
||||||
|
|
||||||
|
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 == list_events.id).values(**update_values)
|
||||||
|
)
|
||||||
|
|
||||||
|
await connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
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=list_events.name,
|
||||||
|
title=list_events.title, # добавлено поле title
|
||||||
|
creator_id=creator_id,
|
||||||
|
created_at=datetime.now(timezone.utc),
|
||||||
|
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 list_events
|
@@ -1,190 +0,0 @@
|
|||||||
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
|
|
||||||
query = (
|
|
||||||
select(
|
|
||||||
list_events_table.c.id,
|
|
||||||
list_events_table.c.name,
|
|
||||||
list_events_table.c.title,
|
|
||||||
list_events_table.c.creator_id,
|
|
||||||
list_events_table.c.created_at,
|
|
||||||
list_events_table.c.schema_,
|
|
||||||
list_events_table.c.state,
|
|
||||||
list_events_table.c.status,
|
|
||||||
)
|
|
||||||
.where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id
|
|
||||||
.order_by(list_events_table.c.id)
|
|
||||||
.offset(first_event)
|
|
||||||
.limit(limit)
|
|
||||||
)
|
|
||||||
|
|
||||||
count_query = (
|
|
||||||
select(func.count())
|
|
||||||
.select_from(list_events_table)
|
|
||||||
.where(list_events_table.c.creator_id == creator_id) # Фильтрация по creator_id
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await connection.execute(query)
|
|
||||||
count_result = await connection.execute(count_query)
|
|
||||||
|
|
||||||
events_data = result.mappings().all()
|
|
||||||
total_count = count_result.scalar()
|
|
||||||
total_pages = math.ceil(total_count / limit)
|
|
||||||
|
|
||||||
# Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные
|
|
||||||
validated_list_event = all_list_event_adapter.validate_python(events_data)
|
|
||||||
|
|
||||||
return AllListEventResponse(
|
|
||||||
list_event=validated_list_event,
|
|
||||||
amount_count=total_count,
|
|
||||||
amount_pages=total_pages,
|
|
||||||
current_page=page,
|
|
||||||
limit=limit,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_listevents_page(connection: AsyncConnection, page, limit) -> Optional[AllListEventResponse]:
|
|
||||||
"""
|
|
||||||
Получает список событий заданного создателя по значениям page и limit.
|
|
||||||
"""
|
|
||||||
|
|
||||||
first_event = page * limit - (limit)
|
|
||||||
|
|
||||||
query = (
|
|
||||||
select(
|
|
||||||
list_events_table.c.id,
|
|
||||||
list_events_table.c.name,
|
|
||||||
list_events_table.c.title,
|
|
||||||
list_events_table.c.creator_id,
|
|
||||||
list_events_table.c.created_at,
|
|
||||||
list_events_table.c.schema,
|
|
||||||
list_events_table.c.state,
|
|
||||||
list_events_table.c.status,
|
|
||||||
)
|
|
||||||
.order_by(list_events_table.c.id)
|
|
||||||
.offset(first_event)
|
|
||||||
.limit(limit)
|
|
||||||
)
|
|
||||||
|
|
||||||
count_query = select(func.count()).select_from(list_events_table)
|
|
||||||
|
|
||||||
result = await connection.execute(query)
|
|
||||||
count_result = await connection.execute(count_query)
|
|
||||||
|
|
||||||
events_data = result.mappings().all()
|
|
||||||
total_count = count_result.scalar()
|
|
||||||
total_pages = math.ceil(total_count / limit)
|
|
||||||
|
|
||||||
# Здесь предполагается, что all_list_event_adapter.validate_python корректно обрабатывает данные
|
|
||||||
validated_list_event = all_list_event_adapter.validate_python(events_data)
|
|
||||||
|
|
||||||
return AllListEventResponse(
|
|
||||||
list_event=validated_list_event,
|
|
||||||
amount_count=total_count,
|
|
||||||
amount_pages=total_pages,
|
|
||||||
current_page=page,
|
|
||||||
limit=limit,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_listevents_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)
|
|
||||||
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):
|
|
||||||
"""
|
|
||||||
Вносит изменеия в нужное поле таблицы list_events_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
|
|
175
api/api/db/logic/process_schema.py
Normal file
175
api/api/db/logic/process_schema.py
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
from typing import Optional
|
||||||
|
import math
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from sqlalchemy import insert, select, func, or_, and_, asc, desc
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
|
from orm.tables.process import process_schema_table
|
||||||
|
|
||||||
|
from api.schemas.process.process_schema import ProcessSchema
|
||||||
|
|
||||||
|
from api.schemas.endpoints.process_schema import (
|
||||||
|
all_process_schema_adapter,
|
||||||
|
AllProcessSchemaResponse,
|
||||||
|
ProcessSchemaFilterDTO,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
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))
|
||||||
|
)
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
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(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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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_by_title(connection: AsyncConnection, title: str) -> Optional[ProcessSchema]:
|
||||||
|
"""
|
||||||
|
Получает process schema по title.
|
||||||
|
"""
|
||||||
|
query = select(process_schema_table).where(process_schema_table.c.title == title)
|
||||||
|
|
||||||
|
process_schema_db_cursor = await connection.execute(query)
|
||||||
|
|
||||||
|
process_schema_data = process_schema_db_cursor.mappings().one_or_none()
|
||||||
|
if not process_schema_data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return ProcessSchema.model_validate(process_schema_data)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_process_schema_by_id(connection: AsyncConnection, id: int) -> Optional[ProcessSchema]:
|
||||||
|
"""
|
||||||
|
Получает process_schema по id.
|
||||||
|
"""
|
||||||
|
query = select(process_schema_table).where(process_schema_table.c.id == id)
|
||||||
|
|
||||||
|
process_schema_db_cursor = await connection.execute(query)
|
||||||
|
|
||||||
|
process_schema_data = process_schema_db_cursor.mappings().one_or_none()
|
||||||
|
if not process_schema_data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return ProcessSchema.model_validate(process_schema_data)
|
||||||
|
|
||||||
|
|
||||||
|
async def 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 == process_schema.id).values(**update_values)
|
||||||
|
)
|
||||||
|
|
||||||
|
await connection.commit()
|
||||||
|
|
||||||
|
|
||||||
|
async def create_process_schema(
|
||||||
|
connection: AsyncConnection, process_schema: ProcessSchema, creator_id: int
|
||||||
|
) -> Optional[ProcessSchema]:
|
||||||
|
"""
|
||||||
|
Создает нове поле в таблице process_schema_table.
|
||||||
|
"""
|
||||||
|
query = insert(process_schema_table).values(
|
||||||
|
title=process_schema.title,
|
||||||
|
description=process_schema.description,
|
||||||
|
owner_id=process_schema.owner_id,
|
||||||
|
creator_id=creator_id,
|
||||||
|
created_at=datetime.now(timezone.utc),
|
||||||
|
settings=process_schema.settings,
|
||||||
|
status=process_schema.status.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
await connection.execute(query)
|
||||||
|
|
||||||
|
await connection.commit()
|
||||||
|
|
||||||
|
return process_schema
|
@@ -1,18 +0,0 @@
|
|||||||
__all__ = ["BigIntegerPK", "SAEnum", "UnsignedInt"]
|
|
||||||
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, Enum, Integer
|
|
||||||
from sqlalchemy.dialects import mysql
|
|
||||||
|
|
||||||
|
|
||||||
# class SAEnum(Enum):
|
|
||||||
# def __init__(self, *enums: object, **kw: Any):
|
|
||||||
# validate_strings = kw.pop("validate_strings", True)
|
|
||||||
# super().__init__(*enums, **kw, validate_strings=validate_strings)
|
|
||||||
|
|
||||||
|
|
||||||
# # https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer
|
|
||||||
|
|
||||||
# BigIntegerPK = BigInteger().with_variant(Integer, "sqlite")
|
|
||||||
UnsignedInt = Integer().with_variant(mysql.INTEGER(unsigned=True), "mysql")
|
|
@@ -1 +0,0 @@
|
|||||||
from . import account, events, process
|
|
@@ -1,65 +0,0 @@
|
|||||||
import enum
|
|
||||||
|
|
||||||
from sqlalchemy import Table, Column, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index
|
|
||||||
from sqlalchemy.sql import func
|
|
||||||
|
|
||||||
from api.db.sql_types import UnsignedInt
|
|
||||||
from api.db import metadata
|
|
||||||
|
|
||||||
|
|
||||||
class AccountRole(enum.StrEnum):
|
|
||||||
OWNER = "OWNER"
|
|
||||||
ADMIN = "ADMIN"
|
|
||||||
EDITOR = "EDITOR"
|
|
||||||
VIEWER = "VIEWER"
|
|
||||||
|
|
||||||
|
|
||||||
class AccountStatus(enum.StrEnum):
|
|
||||||
ACTIVE = "ACTIVE"
|
|
||||||
DISABLED = "DISABLED"
|
|
||||||
BLOCKED = "BLOCKED"
|
|
||||||
DELETED = "DELETED"
|
|
||||||
|
|
||||||
|
|
||||||
account_table = Table(
|
|
||||||
"account",
|
|
||||||
metadata,
|
|
||||||
Column("id", UnsignedInt, primary_key=True, autoincrement=True),
|
|
||||||
Column("name", String(100), nullable=False),
|
|
||||||
Column("login", String(100), nullable=False),
|
|
||||||
Column("email", String(100), nullable=True),
|
|
||||||
Column("bind_tenant_id", String(40), nullable=True),
|
|
||||||
Column("role", SQLAEnum(AccountRole), nullable=False),
|
|
||||||
Column("meta", JSON, default={}),
|
|
||||||
Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=True),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("status", SQLAEnum(AccountStatus), nullable=False),
|
|
||||||
Index("idx_login", "login"),
|
|
||||||
Index("idx_name", "name"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class KeyType(enum.StrEnum):
|
|
||||||
PASSWORD = "PASSWORD"
|
|
||||||
ACCESS_TOKEN = "ACCESS_TOKEN"
|
|
||||||
REFRESH_TOKEN = "REFRESH_TOKEN"
|
|
||||||
API_KEY = "API_KEY"
|
|
||||||
|
|
||||||
|
|
||||||
class KeyStatus(enum.StrEnum):
|
|
||||||
ACTIVE = "ACTIVE"
|
|
||||||
EXPIRED = "EXPIRED"
|
|
||||||
DELETED = "DELETED"
|
|
||||||
|
|
||||||
|
|
||||||
account_keyring_table = Table(
|
|
||||||
"account_keyring",
|
|
||||||
metadata,
|
|
||||||
Column("owner_id", UnsignedInt, ForeignKey("account.id"), primary_key=True, nullable=False),
|
|
||||||
Column("key_type", SQLAEnum(KeyType), primary_key=True, nullable=False),
|
|
||||||
Column("key_id", String(40), primary_key=True, default=None),
|
|
||||||
Column("key_value", String(512), nullable=False),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("expiry", DateTime(timezone=True), nullable=True),
|
|
||||||
Column("status", SQLAEnum(KeyStatus), nullable=False),
|
|
||||||
)
|
|
@@ -1,34 +0,0 @@
|
|||||||
import enum
|
|
||||||
|
|
||||||
from sqlalchemy import Table, Column, Integer, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index
|
|
||||||
from sqlalchemy.sql import func
|
|
||||||
from enum import Enum, auto
|
|
||||||
|
|
||||||
from api.db.sql_types import UnsignedInt
|
|
||||||
|
|
||||||
from api.db import metadata
|
|
||||||
|
|
||||||
|
|
||||||
class EventState(enum.StrEnum):
|
|
||||||
AUTO = "AUTO"
|
|
||||||
DESCRIPTED = "DESCRIPTED"
|
|
||||||
|
|
||||||
|
|
||||||
class EventStatus(enum.StrEnum):
|
|
||||||
ACTIVE = "ACTIVE"
|
|
||||||
DISABLED = "DISABLED"
|
|
||||||
DELETED = "DELETED"
|
|
||||||
|
|
||||||
|
|
||||||
list_events_table = Table(
|
|
||||||
"list_events",
|
|
||||||
metadata,
|
|
||||||
Column("id", UnsignedInt, primary_key=True, autoincrement=True),
|
|
||||||
Column("name", String(40, collation="latin1_bin"), nullable=False, unique=True),
|
|
||||||
Column("title", String(64), nullable=False),
|
|
||||||
Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("schema", JSON, default={}),
|
|
||||||
Column("state", SQLAEnum(EventState), nullable=False),
|
|
||||||
Column("status", SQLAEnum(EventStatus), nullable=False),
|
|
||||||
)
|
|
@@ -1,108 +0,0 @@
|
|||||||
import enum
|
|
||||||
|
|
||||||
from sqlalchemy import (
|
|
||||||
Table,
|
|
||||||
Column,
|
|
||||||
Integer,
|
|
||||||
String,
|
|
||||||
Text,
|
|
||||||
Enum as SQLAEnum,
|
|
||||||
JSON,
|
|
||||||
ForeignKey,
|
|
||||||
DateTime,
|
|
||||||
Index,
|
|
||||||
PrimaryKeyConstraint,
|
|
||||||
)
|
|
||||||
from sqlalchemy.sql import func
|
|
||||||
from enum import Enum, auto
|
|
||||||
|
|
||||||
from api.db.sql_types import UnsignedInt
|
|
||||||
|
|
||||||
from api.db import metadata
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessStatus(enum.StrEnum):
|
|
||||||
ACTIVE = "ACTIVE"
|
|
||||||
STOPPING = "STOPPING"
|
|
||||||
STOPPED = "STOPPED"
|
|
||||||
DELETED = "DELETED"
|
|
||||||
|
|
||||||
|
|
||||||
process_schema_table = Table(
|
|
||||||
"process_schema",
|
|
||||||
metadata,
|
|
||||||
Column("id", UnsignedInt, primary_key=True, autoincrement=True),
|
|
||||||
Column("title", String(100), nullable=False),
|
|
||||||
Column("description", Text, nullable=False),
|
|
||||||
Column("owner_id", UnsignedInt, ForeignKey("account.id"), nullable=False),
|
|
||||||
Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("settings", JSON, default={}),
|
|
||||||
Column("status", SQLAEnum(ProcessStatus), nullable=False),
|
|
||||||
Index(
|
|
||||||
"idx_owner_id",
|
|
||||||
"owner_id",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
process_version_archive_table = Table(
|
|
||||||
"process_version_archive",
|
|
||||||
metadata,
|
|
||||||
Column("id", UnsignedInt, autoincrement=True, nullable=False),
|
|
||||||
Column("ps_id", UnsignedInt, ForeignKey("process_schema.id"), nullable=False),
|
|
||||||
Column("version", UnsignedInt, default=1, nullable=False),
|
|
||||||
Column("snapshot", JSON, default={}),
|
|
||||||
Column("owner_id", UnsignedInt, ForeignKey("account.id"), nullable=False),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("is_last", UnsignedInt, default=0),
|
|
||||||
PrimaryKeyConstraint("id", "version"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class NodeStatus(enum.StrEnum):
|
|
||||||
ACTIVE = "ACTIVE"
|
|
||||||
DISABLED = "DISABLED"
|
|
||||||
DELETED = "DELETED"
|
|
||||||
|
|
||||||
|
|
||||||
class NodeType(Enum):
|
|
||||||
TYPE1 = "Type1"
|
|
||||||
TYPE2 = "Type2"
|
|
||||||
TYPE3 = "Type3"
|
|
||||||
|
|
||||||
|
|
||||||
ps_node_table = Table(
|
|
||||||
"ps_node",
|
|
||||||
metadata,
|
|
||||||
Column("id", UnsignedInt, autoincrement=True, primary_key=True, nullable=False),
|
|
||||||
Column("ps_id", UnsignedInt, ForeignKey("process_schema.id"), nullable=False),
|
|
||||||
Column("node_type", SQLAEnum(NodeType), nullable=False),
|
|
||||||
Column("settings", JSON, default={}),
|
|
||||||
Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("status", SQLAEnum(NodeStatus), nullable=False),
|
|
||||||
Index("idx_ps_id", "ps_id"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class NodeLinkStatus(enum.StrEnum):
|
|
||||||
ACTIVE = "ACTIVE"
|
|
||||||
STOPPING = "STOPPING"
|
|
||||||
STOPPED = "STOPPED"
|
|
||||||
DELETED = "DELETED"
|
|
||||||
|
|
||||||
|
|
||||||
node_link_table = Table(
|
|
||||||
"node_link",
|
|
||||||
metadata,
|
|
||||||
Column("id", UnsignedInt, autoincrement=True, primary_key=True, nullable=False),
|
|
||||||
Column("link_name", String(20), nullable=False),
|
|
||||||
Column("node_id", UnsignedInt, ForeignKey("ps_node.id"), nullable=False),
|
|
||||||
Column("next_node_id", UnsignedInt, ForeignKey("ps_node.id"), nullable=False),
|
|
||||||
Column("settings", JSON, default={}),
|
|
||||||
Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False),
|
|
||||||
Column("created_at", DateTime(timezone=True), server_default=func.now()),
|
|
||||||
Column("status", SQLAEnum(NodeLinkStatus), nullable=False),
|
|
||||||
Index("idx_node_id", "node_id"),
|
|
||||||
Index("idx_next_node_id", "next_node_id"),
|
|
||||||
)
|
|
@@ -2,9 +2,10 @@ from api.endpoints.auth import api_router as auth_router
|
|||||||
from api.endpoints.profile import api_router as profile_router
|
from api.endpoints.profile import api_router as profile_router
|
||||||
from api.endpoints.account import api_router as account_router
|
from api.endpoints.account import api_router as account_router
|
||||||
from api.endpoints.keyring import api_router as keyring_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]
|
list_of_routes = [auth_router, profile_router, account_router, keyring_router, listevents_router, processschema_router]
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"list_of_routes",
|
"list_of_routes",
|
||||||
|
@@ -1,26 +1,22 @@
|
|||||||
from fastapi import (
|
from typing import List, Optional
|
||||||
APIRouter,
|
|
||||||
Depends,
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
HTTPException,
|
from orm.tables.account import AccountStatus
|
||||||
status,
|
|
||||||
)
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
from api.db.connection.session import get_connection_dep
|
from api.db.connection.session import get_connection_dep
|
||||||
from api.db.logic.account import (
|
from api.db.logic.account import (
|
||||||
create_user,
|
create_user,
|
||||||
get_user_accaunt_page,
|
get_user_account_page_DTO,
|
||||||
get_user_by_id,
|
get_user_by_id,
|
||||||
get_user_by_login,
|
get_user_by_login,
|
||||||
update_user_by_id,
|
update_user_by_id,
|
||||||
)
|
)
|
||||||
from api.db.logic.keyring import create_password_key, update_password_key
|
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.account.account import User
|
||||||
from api.schemas.base import bearer_schema
|
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, UserFilterDTO, UserUpdate
|
||||||
from api.services.auth import get_current_user
|
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
|
from api.services.user_role_validation import db_user_role_validation
|
||||||
|
|
||||||
api_router = APIRouter(
|
api_router = APIRouter(
|
||||||
@@ -31,14 +27,33 @@ api_router = APIRouter(
|
|||||||
|
|
||||||
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllUserResponse)
|
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllUserResponse)
|
||||||
async def get_all_account(
|
async def get_all_account(
|
||||||
page: int = 1,
|
page: int = Query(1, description="Page number", gt=0),
|
||||||
limit: int = 10,
|
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),
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
current_user=Depends(get_current_user),
|
current_user=Depends(get_current_user),
|
||||||
):
|
):
|
||||||
authorize_user = await db_user_role_validation(connection, 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:
|
if user_list is None:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Accounts not found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Accounts not found")
|
||||||
@@ -46,7 +61,7 @@ async def get_all_account(
|
|||||||
return user_list
|
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(
|
async def get_account(
|
||||||
user_id: int,
|
user_id: int,
|
||||||
connection: AsyncConnection = Depends(get_connection_dep),
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
@@ -62,7 +77,7 @@ async def get_account(
|
|||||||
return user
|
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(
|
async def create_account(
|
||||||
user: UserCreate,
|
user: UserCreate,
|
||||||
connection: AsyncConnection = Depends(get_connection_dep),
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
@@ -98,14 +113,12 @@ async def update_account(
|
|||||||
if user_update.password is not None:
|
if user_update.password is not None:
|
||||||
await update_password_key(connection, user.id, user_update.password)
|
await update_password_key(connection, user.id, user_update.password)
|
||||||
|
|
||||||
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
|
return user
|
||||||
|
|
||||||
user_update_data = UserUpdate.model_validate({**user.model_dump(), **update_values})
|
await update_user_by_id(connection, updated_values, user)
|
||||||
|
|
||||||
await update_user_by_id(connection, update_values, user)
|
|
||||||
|
|
||||||
user = await get_user_by_id(connection, user_id)
|
user = await get_user_by_id(connection, user_id)
|
||||||
|
|
||||||
@@ -126,12 +139,12 @@ async def delete_account(
|
|||||||
|
|
||||||
user_update = UserUpdate(status=AccountStatus.DELETED.value)
|
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
|
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)
|
||||||
|
|
||||||
|
@@ -1,31 +1,19 @@
|
|||||||
from fastapi import (
|
from fastapi import (
|
||||||
APIRouter,
|
APIRouter,
|
||||||
Body,
|
|
||||||
Depends,
|
Depends,
|
||||||
Form,
|
|
||||||
HTTPException,
|
HTTPException,
|
||||||
Response,
|
|
||||||
status,
|
status,
|
||||||
)
|
)
|
||||||
|
from orm.tables.account import KeyStatus
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
from api.db.connection.session import get_connection_dep
|
from api.db.connection.session import get_connection_dep
|
||||||
|
from api.db.logic.keyring import create_key, get_key_by_id, update_key_by_id
|
||||||
from api.db.logic.keyring import get_key_by_id, create_key, update_key_by_id
|
from api.schemas.account.account_keyring import AccountKeyring
|
||||||
|
|
||||||
|
|
||||||
from api.db.tables.account import KeyStatus
|
|
||||||
from api.schemas.base import bearer_schema
|
from api.schemas.base import bearer_schema
|
||||||
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate
|
from api.schemas.endpoints.account_keyring import AccountKeyringUpdate
|
||||||
|
|
||||||
from api.schemas.account.account_keyring import AccountKeyring
|
|
||||||
from api.services.auth import get_current_user
|
from api.services.auth import get_current_user
|
||||||
|
|
||||||
from api.services.user_role_validation import db_user_role_validation
|
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(
|
api_router = APIRouter(
|
||||||
prefix="/keyring",
|
prefix="/keyring",
|
||||||
@@ -87,14 +75,12 @@ async def update_keyring(
|
|||||||
if keyring is None:
|
if keyring is None:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="keyring not found")
|
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
|
return keyring
|
||||||
|
|
||||||
keyring_update_data = AccountKeyring.model_validate({**keyring.model_dump(), **update_values})
|
await update_key_by_id(connection, updated_values, keyring)
|
||||||
|
|
||||||
await update_key_by_id(connection, update_values, keyring)
|
|
||||||
|
|
||||||
keyring = await get_key_by_id(connection, key_id)
|
keyring = await get_key_by_id(connection, key_id)
|
||||||
|
|
||||||
@@ -116,12 +102,12 @@ async def delete_keyring(
|
|||||||
|
|
||||||
keyring_update = AccountKeyringUpdate(status=KeyStatus.DELETED.value)
|
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
|
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)
|
keyring = await get_key_by_id(connection, key_id)
|
||||||
|
|
||||||
|
169
api/api/endpoints/list_events.py
Normal file
169
api/api/endpoints/list_events.py
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
|
from orm.tables.events import EventStatus
|
||||||
|
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.list_events import (
|
||||||
|
create_list_events,
|
||||||
|
get_list_events_by_id,
|
||||||
|
get_list_events_by_name,
|
||||||
|
get_list_events_page_DTO,
|
||||||
|
update_list_events_by_id,
|
||||||
|
)
|
||||||
|
from api.schemas.base import bearer_schema
|
||||||
|
from api.schemas.endpoints.list_events import AllListEventResponse, ListEventFilterDTO, ListEventUpdate
|
||||||
|
from api.schemas.events.list_events import ListEvent
|
||||||
|
from api.services.auth import get_current_user
|
||||||
|
from api.services.user_role_validation import (
|
||||||
|
db_user_role_validation_for_list_events_and_process_schema,
|
||||||
|
db_user_role_validation_for_list_events_and_process_schema_by_list_event_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
api_router = APIRouter(
|
||||||
|
prefix="/list_events",
|
||||||
|
tags=["list events"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllListEventResponse)
|
||||||
|
async def get_all_list_events(
|
||||||
|
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 {}),
|
||||||
|
**({"state": state_filter} if state_filter else {}),
|
||||||
|
**({"creator_id": [str(creator_id)]} if creator_id 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_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_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")
|
||||||
|
|
||||||
|
return list_events_page
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.get("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||||
|
async def get_list_events(
|
||||||
|
list_events_id: int,
|
||||||
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
|
current_user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
list_events_validation = await get_list_events_by_id(connection, list_events_id)
|
||||||
|
|
||||||
|
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_list_events_and_process_schema_by_list_event_id(
|
||||||
|
connection, current_user, list_events_validation.creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if list_events_id is None:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="List events not found")
|
||||||
|
|
||||||
|
return list_events_validation
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||||
|
async def create_list_events(
|
||||||
|
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)
|
||||||
|
list_events_validation = await get_list_events_by_name(connection, list_events.name)
|
||||||
|
|
||||||
|
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(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST, detail="An List events with this information already exists."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.put("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||||
|
async def update_list_events(
|
||||||
|
list_events_id: int,
|
||||||
|
list_events_update: ListEventUpdate,
|
||||||
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
|
current_user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
list_events_validation = await get_list_events_by_id(connection, list_events_id)
|
||||||
|
|
||||||
|
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_list_events_and_process_schema_by_list_event_id(
|
||||||
|
connection, current_user, list_events_validation.creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
updated_values = list_events_update.model_dump(by_alias=True, exclude_none=True)
|
||||||
|
|
||||||
|
if not updated_values:
|
||||||
|
return list_events_validation
|
||||||
|
|
||||||
|
await update_list_events_by_id(connection, updated_values, list_events_validation)
|
||||||
|
|
||||||
|
list_events = await get_list_events_by_id(connection, list_events_id)
|
||||||
|
|
||||||
|
return list_events
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.delete("/{list_events_id}", dependencies=[Depends(bearer_schema)], response_model=ListEvent)
|
||||||
|
async def delete_list_events(
|
||||||
|
list_events_id: int,
|
||||||
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
|
current_user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
list_events_validation = await get_list_events_by_id(connection, list_events_id)
|
||||||
|
|
||||||
|
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_list_events_and_process_schema_by_list_event_id(
|
||||||
|
connection, current_user, list_events_validation.creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
list_events_update = ListEventUpdate(status=EventStatus.DELETED.value)
|
||||||
|
|
||||||
|
updated_values = list_events_update.model_dump(by_alias=True, exclude_none=True)
|
||||||
|
|
||||||
|
if not updated_values:
|
||||||
|
return list_events_validation
|
||||||
|
|
||||||
|
await update_list_events_by_id(connection, updated_values, list_events_validation)
|
||||||
|
|
||||||
|
list_events = await get_list_events_by_id(connection, list_events_id)
|
||||||
|
|
||||||
|
return list_events
|
@@ -1,169 +0,0 @@
|
|||||||
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)
|
|
||||||
listevents_new = await get_listevents_by_name(connection, listevents.name)
|
|
||||||
return listevents_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
|
|
169
api/api/endpoints/process_schema.py
Normal file
169
api/api/endpoints/process_schema.py
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
|
from orm.tables.process import ProcessStatus
|
||||||
|
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.process_schema import (
|
||||||
|
create_process_schema,
|
||||||
|
get_process_schema_by_id,
|
||||||
|
get_process_schema_by_title,
|
||||||
|
get_process_schema_page_DTO,
|
||||||
|
update_process_schema_by_id,
|
||||||
|
)
|
||||||
|
from api.schemas.base import bearer_schema
|
||||||
|
from api.schemas.endpoints.process_schema import AllProcessSchemaResponse, ProcessSchemaFilterDTO, ProcessSchemaUpdate
|
||||||
|
from api.schemas.process.process_schema import ProcessSchema
|
||||||
|
from api.services.auth import get_current_user
|
||||||
|
from api.services.user_role_validation import (
|
||||||
|
db_user_role_validation_for_list_events_and_process_schema,
|
||||||
|
db_user_role_validation_for_list_events_and_process_schema_by_list_event_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
api_router = APIRouter(
|
||||||
|
prefix="/process_schema",
|
||||||
|
tags=["process schema"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.get("", dependencies=[Depends(bearer_schema)], response_model=AllProcessSchemaResponse)
|
||||||
|
async def get_all_process_schema(
|
||||||
|
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_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)]
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
return process_schema_page
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.get("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
|
||||||
|
async def get_process_schema(
|
||||||
|
process_schema_id: int,
|
||||||
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
|
current_user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
process_schema_validation = await get_process_schema_by_id(connection, process_schema_id)
|
||||||
|
|
||||||
|
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_list_events_and_process_schema_by_list_event_id(
|
||||||
|
connection, current_user, process_schema_validation.creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if process_schema_id is None:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Process schema not found")
|
||||||
|
|
||||||
|
return process_schema_validation
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.post("", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
|
||||||
|
async def create_processschema(
|
||||||
|
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)
|
||||||
|
process_schema_validation = await get_process_schema_by_title(connection, process_schema.title)
|
||||||
|
|
||||||
|
if process_schema_validation is None:
|
||||||
|
await create_process_schema(connection, process_schema, user_validation.id)
|
||||||
|
process_schema_new = await get_process_schema_by_title(connection, process_schema.title)
|
||||||
|
return process_schema_new
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST, detail="An process schema with this information already exists."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.put("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
|
||||||
|
async def update_process_schema(
|
||||||
|
process_schema_id: int,
|
||||||
|
process_schema_update: ProcessSchemaUpdate,
|
||||||
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
|
current_user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
process_schema_validation = await get_process_schema_by_id(connection, process_schema_id)
|
||||||
|
|
||||||
|
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_list_events_and_process_schema_by_list_event_id(
|
||||||
|
connection, current_user, process_schema_validation.creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
updated_values = process_schema_update.model_dump(by_alias=True, exclude_none=True)
|
||||||
|
|
||||||
|
if not updated_values:
|
||||||
|
return process_schema_validation
|
||||||
|
|
||||||
|
await update_process_schema_by_id(connection, updated_values, process_schema_validation)
|
||||||
|
|
||||||
|
process_schema = await get_process_schema_by_id(connection, process_schema_id)
|
||||||
|
|
||||||
|
return process_schema
|
||||||
|
|
||||||
|
|
||||||
|
@api_router.delete("/{process_schema_id}", dependencies=[Depends(bearer_schema)], response_model=ProcessSchema)
|
||||||
|
async def delete_process_schema(
|
||||||
|
process_schema_id: int,
|
||||||
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
|
current_user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
process_schema_validation = await get_process_schema_by_id(connection, process_schema_id)
|
||||||
|
|
||||||
|
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_list_events_and_process_schema_by_list_event_id(
|
||||||
|
connection, current_user, process_schema_validation.creator_id
|
||||||
|
)
|
||||||
|
|
||||||
|
process_schema_update = ProcessSchemaUpdate(status=ProcessStatus.DELETED.value)
|
||||||
|
|
||||||
|
updated_values = process_schema_update.model_dump(by_alias=True, exclude_none=True)
|
||||||
|
|
||||||
|
if not updated_values:
|
||||||
|
return process_schema_validation
|
||||||
|
|
||||||
|
await update_process_schema_by_id(connection, updated_values, process_schema_validation)
|
||||||
|
|
||||||
|
process_schema = await get_process_schema_by_id(connection, process_schema_id)
|
||||||
|
|
||||||
|
return process_schema
|
@@ -1,26 +1,17 @@
|
|||||||
from fastapi import (
|
from fastapi import (
|
||||||
APIRouter,
|
APIRouter,
|
||||||
Body,
|
|
||||||
Depends,
|
Depends,
|
||||||
Form,
|
|
||||||
HTTPException,
|
HTTPException,
|
||||||
Request,
|
|
||||||
Response,
|
|
||||||
status,
|
status,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
from api.db.connection.session import get_connection_dep
|
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.db.logic.account import get_user_by_id, get_user_by_login, update_user_by_id
|
||||||
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
|
from api.schemas.account.account import User
|
||||||
|
from api.schemas.base import bearer_schema
|
||||||
|
from api.schemas.endpoints.account import UserUpdate
|
||||||
|
from api.services.auth import get_current_user
|
||||||
|
|
||||||
api_router = APIRouter(
|
api_router = APIRouter(
|
||||||
prefix="/profile",
|
prefix="/profile",
|
||||||
@@ -42,7 +33,7 @@ async def get_profile(
|
|||||||
|
|
||||||
@api_router.put("", dependencies=[Depends(bearer_schema)], response_model=User)
|
@api_router.put("", dependencies=[Depends(bearer_schema)], response_model=User)
|
||||||
async def update_profile(
|
async def update_profile(
|
||||||
user_updata: UserUpdate,
|
user_update: UserUpdate,
|
||||||
connection: AsyncConnection = Depends(get_connection_dep),
|
connection: AsyncConnection = Depends(get_connection_dep),
|
||||||
current_user=Depends(get_current_user),
|
current_user=Depends(get_current_user),
|
||||||
):
|
):
|
||||||
@@ -50,15 +41,15 @@ async def update_profile(
|
|||||||
if user is None:
|
if user is None:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found")
|
||||||
|
|
||||||
if user_updata.role == None and user_updata.login == None:
|
if user_update.role is None and user_update.login is None:
|
||||||
update_values = update_user_data_changes(user_updata, user)
|
updated_values = user_update.model_dump(by_alias=True, exclude_none=True)
|
||||||
|
|
||||||
if update_values is None:
|
if updated_values is None:
|
||||||
return user
|
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
|
return user
|
||||||
else:
|
else:
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import datetime
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from orm.tables.account import AccountRole, AccountStatus
|
||||||
from pydantic import EmailStr, Field
|
from pydantic import EmailStr, Field
|
||||||
from api.db.tables.account import AccountRole, AccountStatus
|
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import datetime
|
|
||||||
from typing import Optional
|
|
||||||
from pydantic import Field
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from api.db.tables.account import KeyType, KeyStatus
|
from typing import Optional
|
||||||
|
|
||||||
|
from orm.tables.account import KeyStatus, KeyType
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List, Optional
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
from orm.tables.account import AccountRole, AccountStatus
|
||||||
from pydantic import EmailStr, Field, TypeAdapter
|
from pydantic import EmailStr, Field, TypeAdapter
|
||||||
|
|
||||||
from api.db.tables.account import AccountRole, AccountStatus
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
|
||||||
@@ -36,6 +36,8 @@ class AllUser(Base):
|
|||||||
email: Optional[EmailStr] = None
|
email: Optional[EmailStr] = None
|
||||||
bind_tenant_id: Optional[str] = None
|
bind_tenant_id: Optional[str] = None
|
||||||
role: AccountRole
|
role: AccountRole
|
||||||
|
meta: Optional[dict] = None
|
||||||
|
creator_id: Optional[int] = None
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
status: AccountStatus
|
status: AccountStatus
|
||||||
|
|
||||||
@@ -49,3 +51,10 @@ class AllUserResponse(Base):
|
|||||||
|
|
||||||
|
|
||||||
all_user_adapter = TypeAdapter(List[AllUser])
|
all_user_adapter = TypeAdapter(List[AllUser])
|
||||||
|
|
||||||
|
|
||||||
|
class UserFilterDTO(Base):
|
||||||
|
pagination: Dict[str, int]
|
||||||
|
search: Optional[str] = None
|
||||||
|
order: Optional[Dict[str, str]] = None
|
||||||
|
filters: Optional[Dict[str, List[str]]] = None
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
import datetime
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from orm.tables.account import KeyStatus, KeyType
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from datetime import datetime
|
|
||||||
from api.db.tables.account import KeyType, KeyStatus
|
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
|
||||||
# Таблица для получения информации из запроса
|
# Таблица для получения информации из запроса
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
from pydantic import Field, TypeAdapter
|
|
||||||
from typing import Optional, Dict, Any, List
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
from orm.tables.events import EventState, EventStatus
|
||||||
|
from pydantic import Field, TypeAdapter
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
from api.db.tables.events import EventState, EventStatus
|
|
||||||
|
|
||||||
|
|
||||||
class ListEventUpdate(Base):
|
class ListEventUpdate(Base):
|
||||||
@@ -35,3 +35,10 @@ class AllListEventResponse(Base):
|
|||||||
|
|
||||||
|
|
||||||
all_list_event_adapter = TypeAdapter(List[AllListEvent])
|
all_list_event_adapter = TypeAdapter(List[AllListEvent])
|
||||||
|
|
||||||
|
|
||||||
|
class ListEventFilterDTO(Base):
|
||||||
|
pagination: Dict[str, int]
|
||||||
|
search: Optional[str] = None
|
||||||
|
order: Optional[Dict[str, str]] = None
|
||||||
|
filters: Optional[Dict[str, List[str]]] = None
|
||||||
|
44
api/api/schemas/endpoints/process_schema.py
Normal file
44
api/api/schemas/endpoints/process_schema.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
from orm.tables.process import ProcessStatus
|
||||||
|
from pydantic import Field, TypeAdapter
|
||||||
|
|
||||||
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessSchemaUpdate(Base):
|
||||||
|
title: Optional[str] = Field(None, max_length=100)
|
||||||
|
description: Optional[str] = None
|
||||||
|
owner_id: Optional[int] = None
|
||||||
|
settings: Optional[Dict[str, Any]] = None
|
||||||
|
status: Optional[ProcessStatus] = None
|
||||||
|
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessSchemaFilterDTO(Base):
|
||||||
|
pagination: Dict[str, int]
|
||||||
|
search: Optional[str] = None
|
||||||
|
order: Optional[Dict[str, str]] = None
|
||||||
|
filters: Optional[Dict[str, List[str]]] = None
|
@@ -1,9 +1,10 @@
|
|||||||
from pydantic import Field
|
|
||||||
from typing import Dict, Any
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from orm.tables.events import EventState, EventStatus
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
from api.db.tables.events import EventState, EventStatus
|
|
||||||
|
|
||||||
|
|
||||||
class ListEvent(Base):
|
class ListEvent(Base):
|
||||||
|
@@ -1,18 +1,12 @@
|
|||||||
from pydantic import Field
|
|
||||||
from typing import Dict, Any
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from orm.tables.process import NodeStatus
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
|
||||||
ACTIVE = "Active"
|
|
||||||
STOPPING = "Stopping"
|
|
||||||
STOPPED = "Stopped"
|
|
||||||
DELETED = "Deleted"
|
|
||||||
|
|
||||||
|
|
||||||
class MyModel(Base):
|
class MyModel(Base):
|
||||||
id: int
|
id: int
|
||||||
link_name: str = Field(..., max_length=20)
|
link_name: str = Field(..., max_length=20)
|
||||||
@@ -21,4 +15,4 @@ class MyModel(Base):
|
|||||||
settings: Dict[str, Any]
|
settings: Dict[str, Any]
|
||||||
creator_id: int
|
creator_id: int
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
status: Status
|
status: NodeStatus
|
||||||
|
@@ -1,18 +1,12 @@
|
|||||||
from pydantic import Field
|
|
||||||
from typing import Dict, Any
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from orm.tables.process import ProcessStatus
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
|
||||||
ACTIVE = "Active"
|
|
||||||
STOPPING = "Stopping"
|
|
||||||
STOPPED = "Stopped"
|
|
||||||
DELETED = "Deleted"
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessSchema(Base):
|
class ProcessSchema(Base):
|
||||||
id: int
|
id: int
|
||||||
title: str = Field(..., max_length=100)
|
title: str = Field(..., max_length=100)
|
||||||
@@ -21,4 +15,4 @@ class ProcessSchema(Base):
|
|||||||
creator_id: int
|
creator_id: int
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
settings: Dict[str, Any]
|
settings: Dict[str, Any]
|
||||||
status: Status
|
status: ProcessStatus
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
from typing import Dict, Any
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
@@ -1,20 +1,11 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, Any
|
from typing import Any, Dict
|
||||||
from enum import Enum
|
|
||||||
|
from orm.tables.process import NodeStatus, NodeType
|
||||||
|
|
||||||
from api.schemas.base import Base
|
from api.schemas.base import Base
|
||||||
|
|
||||||
|
|
||||||
class NodeType(Enum):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
|
||||||
ACTIVE = "Active"
|
|
||||||
DISABLED = "Disabled"
|
|
||||||
DELETED = "Deleted"
|
|
||||||
|
|
||||||
|
|
||||||
class Ps_Node(Base):
|
class Ps_Node(Base):
|
||||||
id: int
|
id: int
|
||||||
ps_id: int
|
ps_id: int
|
||||||
@@ -22,4 +13,4 @@ class Ps_Node(Base):
|
|||||||
settings: dict
|
settings: dict
|
||||||
creator_id: Dict[str, Any]
|
creator_id: Dict[str, Any]
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
status: Status
|
status: NodeStatus
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import HTTPException, Request
|
from fastapi import HTTPException, Request
|
||||||
|
from orm.tables.account import AccountStatus
|
||||||
from sqlalchemy.ext.asyncio import AsyncConnection
|
from sqlalchemy.ext.asyncio import AsyncConnection
|
||||||
|
|
||||||
from api.db.logic.auth import get_user
|
from api.db.logic.auth import get_user
|
||||||
from api.db.tables.account import AccountStatus
|
|
||||||
from api.schemas.endpoints.account import AllUser
|
from api.schemas.endpoints.account import AllUser
|
||||||
from api.utils.hasher import hasher
|
from api.utils.hasher import hasher
|
||||||
|
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
from fastapi_jwt_auth import AuthJWT
|
import re
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from re import escape
|
||||||
|
|
||||||
from fastapi import (
|
from fastapi import (
|
||||||
Request,
|
Request,
|
||||||
status,
|
status,
|
||||||
)
|
)
|
||||||
|
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from api.config import get_settings
|
from fastapi_jwt_auth import AuthJWT
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
|
||||||
import re
|
from api.config import get_settings
|
||||||
from re import escape
|
|
||||||
|
|
||||||
|
|
||||||
class MiddlewareAccessTokenValidadtion(BaseHTTPMiddleware):
|
class MiddlewareAccessTokenValidadtion(BaseHTTPMiddleware):
|
||||||
|
@@ -1,110 +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
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
@@ -2,8 +2,9 @@ from fastapi import (
|
|||||||
HTTPException,
|
HTTPException,
|
||||||
status,
|
status,
|
||||||
)
|
)
|
||||||
|
from orm.tables.account import AccountRole
|
||||||
|
|
||||||
from api.db.logic.account import get_user_by_login
|
from api.db.logic.account import get_user_by_login
|
||||||
from api.db.tables.account import AccountRole
|
|
||||||
|
|
||||||
|
|
||||||
async def db_user_role_validation(connection, current_user):
|
async def db_user_role_validation(connection, current_user):
|
||||||
@@ -13,7 +14,7 @@ async def db_user_role_validation(connection, current_user):
|
|||||||
return authorize_user
|
return authorize_user
|
||||||
|
|
||||||
|
|
||||||
async def db_user_role_validation_for_listevents_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
|
connection, current_user, current_listevents_creator_id
|
||||||
):
|
):
|
||||||
authorize_user = await get_user_by_login(connection, current_user)
|
authorize_user = await get_user_by_login(connection, current_user)
|
||||||
@@ -23,7 +24,7 @@ async def db_user_role_validation_for_listevents_by_listevent_id(
|
|||||||
return authorize_user
|
return authorize_user
|
||||||
|
|
||||||
|
|
||||||
async def db_user_role_validation_for_listevents(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)
|
authorize_user = await get_user_by_login(connection, current_user)
|
||||||
if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}:
|
if authorize_user.role not in {AccountRole.OWNER, AccountRole.ADMIN}:
|
||||||
return authorize_user, False
|
return authorize_user, False
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from orm.tables.account import account_keyring_table, account_table, AccountRole, KeyStatus, KeyType
|
||||||
|
|
||||||
from api.db.connection.session import get_connection
|
from api.db.connection.session import get_connection
|
||||||
from api.db.tables.account import account_keyring_table, account_table, AccountRole, KeyStatus, KeyType
|
|
||||||
from api.utils.hasher import hasher
|
from api.utils.hasher import hasher
|
||||||
from api.utils.key_id_gen import KeyIdGenerator
|
from api.utils.key_id_gen import KeyIdGenerator
|
||||||
|
|
||||||
|
153
api/poetry.lock
generated
153
api/poetry.lock
generated
@@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aio-pika"
|
name = "aio-pika"
|
||||||
@@ -227,6 +227,25 @@ files = [
|
|||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-library"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Abstract classes library for the Vorkout project"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = []
|
||||||
|
develop = false
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
sqlalchemy = ">=2.0.43,<3.0.0"
|
||||||
|
|
||||||
|
[package.source]
|
||||||
|
type = "git"
|
||||||
|
url = "https://gitea.heado.ru/Vorkout/core.git"
|
||||||
|
reference = "0.1.0"
|
||||||
|
resolved_reference = "96ddb52582660600dbacead4919e67f948e96898"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cryptography"
|
name = "cryptography"
|
||||||
version = "44.0.2"
|
version = "44.0.2"
|
||||||
@@ -1416,83 +1435,83 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlalchemy"
|
name = "sqlalchemy"
|
||||||
version = "2.0.39"
|
version = "2.0.43"
|
||||||
description = "Database Abstraction Library"
|
description = "Database Abstraction Library"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
groups = ["main"]
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:66a40003bc244e4ad86b72abb9965d304726d05a939e8c09ce844d27af9e6d37"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21ba7a08a4253c5825d1db389d4299f64a100ef9800e4624c8bf70d8f136e6ed"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11b9503fa6f8721bef9b8567730f664c5a5153d25e247aadc69247c4bc605227"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:533e0f66c32093a987a30df3ad6ed21170db9d581d0b38e71396c49718fbb1ca"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07097c0a1886c150ef2adba2ff7437e84d40c0f7dcb44a2c2b9c905ccfc6361c"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:cdeff998cb294896a34e5b2f00e383e7c5c4ef3b4bfa375d9104723f15186443"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:788b6ff6728072b313802be13e88113c33696a9a1f2f6d634a97c20f7ef5ccce"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:bcf0724a62a5670e5718957e05c56ec2d6850267ea859f8ad2481838f889b42c"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-win32.whl", hash = "sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-win32.whl", hash = "sha256:c697575d0e2b0a5f0433f679bda22f63873821d991e95a90e9e52aae517b2e32"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp37-cp37m-win_amd64.whl", hash = "sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5"},
|
{file = "SQLAlchemy-2.0.43-cp37-cp37m-win_amd64.whl", hash = "sha256:d34c0f6dbefd2e816e8f341d0df7d4763d382e3f452423e752ffd1e213da2512"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b761a6847f96fdc2d002e29e9e9ac2439c13b919adfd64e8ef49e75f6355c548"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70322986c0c699dca241418fcf18e637a4369e0ec50540a2b907b184c8bca069"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d7e3866eb52d914aea50c9be74184a0feb86f9af8aaaa4daefe52b69378db0b"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:87accdbba88f33efa7b592dc2e8b2a9c2cdbca73db2f9d5c510790428c09c154"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c00e7845d2f692ebfc7d5e4ec1a3fd87698e4337d09e58d6749a16aedfdf8612"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344cd1ec2b3c6bdd5dfde7ba7e3b879e0f8dd44181f16b895940be9b842fd2b6"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:022e436a1cb39b13756cf93b48ecce7aa95382b9cfacceb80a7d263129dfd019"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c5e73ba0d76eefc82ec0219d2301cb33bfe5205ed7a2602523111e2e56ccbd20"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3395e7ed89c6d264d38bea3bfb22ffe868f906a7985d03546ec7dc30221ea980"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9c2e02f06c68092b875d5cbe4824238ab93a7fa35d9c38052c033f7ca45daa18"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-win32.whl", hash = "sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-win32.whl", hash = "sha256:e7a903b5b45b0d9fa03ac6a331e1c1d6b7e0ab41c63b6217b3d10357b83c8b00"},
|
||||||
{file = "SQLAlchemy-2.0.39-cp38-cp38-win_amd64.whl", hash = "sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02"},
|
{file = "sqlalchemy-2.0.43-cp310-cp310-win_amd64.whl", hash = "sha256:4bf0edb24c128b7be0c61cd17eef432e4bef507013292415f3fb7023f02b7d4b"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:52d9b73b8fb3e9da34c2b31e6d99d60f5f99fd8c1225c9dad24aeb74a91e1d29"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f42f23e152e4545157fa367b2435a1ace7571cab016ca26038867eb7df2c3631"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fb1a8c5438e0c5ea51afe9c6564f951525795cf432bed0c028c1cb081276685"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db691fa174e8f7036afefe3061bc40ac2b770718be2862bfb03aabae09051aca"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2b3b4927d0bc03d02ad883f402d5de201dbc8894ac87d2e981e7d87430e60d"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4d3d9b904ad4a6b175a2de0738248822f5ac410f52c2fd389ada0b5262d6a1e3"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-win32.whl", hash = "sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-win32.whl", hash = "sha256:5cda6b51faff2639296e276591808c1726c4a77929cfaa0f514f30a5f6156921"},
|
||||||
{file = "sqlalchemy-2.0.39-cp310-cp310-win_amd64.whl", hash = "sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304"},
|
{file = "sqlalchemy-2.0.43-cp311-cp311-win_amd64.whl", hash = "sha256:c5d1730b25d9a07727d20ad74bc1039bbbb0a6ca24e6769861c1aa5bf2c4c4a8"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:20d81fc2736509d7a2bd33292e489b056cbae543661bb7de7ce9f1c0cd6e7f24"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b9fc27650ff5a2c9d490c13c14906b918b0de1f8fcbb4c992712d8caf40e83"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6772e3ca8a43a65a37c88e2f3e2adfd511b0b1da37ef11ed78dea16aeae85bd9"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a113da919c25f7f641ffbd07fbc9077abd4b3b75097c888ab818f962707eb48"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4286a1139f14b7d70141c67a8ae1582fc2b69105f1b09d9573494eb4bb4b2687"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:529064085be2f4d8a6e5fab12d36ad44f1909a18848fcfbdb59cc6d4bbe48efe"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-win32.whl", hash = "sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-win32.whl", hash = "sha256:b535d35dea8bbb8195e7e2b40059e2253acb2b7579b73c1b432a35363694641d"},
|
||||||
{file = "sqlalchemy-2.0.39-cp311-cp311-win_amd64.whl", hash = "sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f"},
|
{file = "sqlalchemy-2.0.43-cp312-cp312-win_amd64.whl", hash = "sha256:1c6d85327ca688dbae7e2b06d7d84cfe4f3fffa5b5f9e21bb6ce9d0e1a0e0e0a"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2cf5b5ddb69142511d5559c427ff00ec8c0919a1e6c09486e9c32636ea2b9dd"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06205eb98cb3dd52133ca6818bf5542397f1dd1b69f7ea28aa84413897380b06"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-win32.whl", hash = "sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-win32.whl", hash = "sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d"},
|
||||||
{file = "sqlalchemy-2.0.39-cp312-cp312-win_amd64.whl", hash = "sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338"},
|
{file = "sqlalchemy-2.0.43-cp313-cp313-win_amd64.whl", hash = "sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e6aeb2e0932f32950cf56a8b4813cb15ff792fc0c9b3752eaf067cfe298496a"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:61f964a05356f4bca4112e6334ed7c208174511bd56e6b8fc86dad4d024d4185"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46293c39252f93ea0910aababa8752ad628bcce3a10d3f260648dd472256983f"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:136063a68644eca9339d02e6693932116f6a8591ac013b0014479a1de664e40a"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6e2bf13d9256398d037fef09fd8bf9b0bf77876e22647d10761d35593b9ac547"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:44337823462291f17f994d64282a71c51d738fc9ef561bf265f1d0fd9116a782"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-win32.whl", hash = "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-win32.whl", hash = "sha256:13194276e69bb2af56198fef7909d48fd34820de01d9c92711a5fa45497cc7ed"},
|
||||||
{file = "sqlalchemy-2.0.39-cp313-cp313-win_amd64.whl", hash = "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0"},
|
{file = "sqlalchemy-2.0.43-cp38-cp38-win_amd64.whl", hash = "sha256:334f41fa28de9f9be4b78445e68530da3c5fa054c907176460c81494f4ae1f5e"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2600a50d590c22d99c424c394236899ba72f849a02b10e65b4c70149606408b5"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ceb5c832cc30663aeaf5e39657712f4c4241ad1f638d487ef7216258f6d41fe7"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4eff9c270afd23e2746e921e80182872058a7a592017b2713f33f96cc5f82e32"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11f43c39b4b2ec755573952bbcc58d976779d482f6f832d7f33a8d869ae891bf"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:413391b2239db55be14fa4223034d7e13325a1812c8396ecd4f2c08696d5ccad"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:125a7763b263218a80759ad9ae2f3610aaf2c2fbbd78fff088d584edf81f3782"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c379e37b08c6c527181a397212346be39319fb64323741d23e46abd97a400d34"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03d73ab2a37d9e40dec4984d1813d7878e01dbdc742448d44a7341b7a9f408c7"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:805cb481474e111ee3687c9047c5f3286e62496f09c0e82e8853338aaaa348f8"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8cee08f15d9e238ede42e9bbc1d6e7158d0ca4f176e4eab21f88ac819ae3bd7b"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-win32.whl", hash = "sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-win32.whl", hash = "sha256:b3edaec7e8b6dc5cd94523c6df4f294014df67097c8217a89929c99975811414"},
|
||||||
{file = "sqlalchemy-2.0.39-cp39-cp39-win_amd64.whl", hash = "sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a"},
|
{file = "sqlalchemy-2.0.43-cp39-cp39-win_amd64.whl", hash = "sha256:227119ce0a89e762ecd882dc661e0aa677a690c914e358f0dd8932a2e8b2765b"},
|
||||||
{file = "sqlalchemy-2.0.39-py3-none-any.whl", hash = "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f"},
|
{file = "sqlalchemy-2.0.43-py3-none-any.whl", hash = "sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc"},
|
||||||
{file = "sqlalchemy-2.0.39.tar.gz", hash = "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22"},
|
{file = "sqlalchemy-2.0.43.tar.gz", hash = "sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
aiomysql = {version = ">=0.2.0", optional = true, markers = "extra == \"aiomysql\""}
|
aiomysql = {version = ">=0.2.0", optional = true, markers = "extra == \"aiomysql\""}
|
||||||
greenlet = {version = "!=0.4.17", optional = true, markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\") or extra == \"aiomysql\""}
|
greenlet = {version = ">=1", optional = true, markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\") or extra == \"aiomysql\""}
|
||||||
pymysql = {version = "*", optional = true, markers = "extra == \"pymysql\""}
|
pymysql = {version = "*", optional = true, markers = "extra == \"pymysql\""}
|
||||||
typing-extensions = ">=4.6.0"
|
typing-extensions = ">=4.6.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
|
aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"]
|
||||||
aioodbc = ["aioodbc", "greenlet (!=0.4.17)"]
|
aioodbc = ["aioodbc", "greenlet (>=1)"]
|
||||||
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
|
aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"]
|
||||||
asyncio = ["greenlet (!=0.4.17)"]
|
asyncio = ["greenlet (>=1)"]
|
||||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"]
|
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"]
|
||||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"]
|
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"]
|
||||||
mssql = ["pyodbc"]
|
mssql = ["pyodbc"]
|
||||||
mssql-pymssql = ["pymssql"]
|
mssql-pymssql = ["pymssql"]
|
||||||
@@ -1503,7 +1522,7 @@ mysql-connector = ["mysql-connector-python"]
|
|||||||
oracle = ["cx_oracle (>=8)"]
|
oracle = ["cx_oracle (>=8)"]
|
||||||
oracle-oracledb = ["oracledb (>=1.0.1)"]
|
oracle-oracledb = ["oracledb (>=1.0.1)"]
|
||||||
postgresql = ["psycopg2 (>=2.7)"]
|
postgresql = ["psycopg2 (>=2.7)"]
|
||||||
postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
|
postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"]
|
||||||
postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
|
postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
|
||||||
postgresql-psycopg = ["psycopg (>=3.0.7)"]
|
postgresql-psycopg = ["psycopg (>=3.0.7)"]
|
||||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||||
@@ -1933,4 +1952,4 @@ propcache = ">=0.2.0"
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.11,<4.0"
|
python-versions = ">=3.11,<4.0"
|
||||||
content-hash = "5ed129fde2c5d7b3518fbb2fe2ce79f0bad2aa1060304d45a7bc26d35f7ab46b"
|
content-hash = "0ac41110571b3bba38672fceef1c107864b8582378c6afba6418e05f99a75da1"
|
||||||
|
@@ -17,6 +17,7 @@ dependencies = [
|
|||||||
"pydantic[email] (>=2.11.3,<3.0.0)",
|
"pydantic[email] (>=2.11.3,<3.0.0)",
|
||||||
"python-multipart (>=0.0.20,<0.0.21)",
|
"python-multipart (>=0.0.20,<0.0.21)",
|
||||||
"fastapi-jwt-auth @ git+https://github.com/vvpreo/fastapi-jwt-auth",
|
"fastapi-jwt-auth @ git+https://github.com/vvpreo/fastapi-jwt-auth",
|
||||||
|
"core-library @ git+https://gitea.heado.ru/Vorkout/core.git@0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user