refactoring

This commit is contained in:
Alexander Kalinovsky
2025-01-09 13:11:10 +01:00
parent 7793a0cb77
commit 3898a333fa
29 changed files with 1065 additions and 381 deletions

View File

@@ -1,4 +1,4 @@
from typing import get_args, get_origin
from typing import get_args, get_origin, TYPE_CHECKING
from aiogram import Router, F
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
@@ -9,7 +9,6 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
from logging import getLogger
from sqlmodel.ext.asyncio.session import AsyncSession
from ....main import QBotApp
from ....model.bot_entity import BotEntity
from ....model.bot_enum import BotEnum
from ....model.owned_bot_entity import OwnedBotEntity
@@ -21,25 +20,33 @@ from ....utils import serialize, deserialize, get_user_permissions
from ..context import ContextData, CallbackCommand, CommandContext
from ..common import get_send_message, get_local_text, get_entity_descriptor, get_callable_str, get_value_repr
if TYPE_CHECKING:
from ....main import QBotApp
logger = getLogger(__name__)
router = Router()
@router.callback_query(ContextData.filter(F.command == CallbackCommand.ENTITY_ITEM))
async def entity_item_callback(query: CallbackQuery, callback_data: ContextData, **kwargs):
async def entity_item_callback(query: CallbackQuery, **kwargs):
await clear_state(state = kwargs["state"])
stack = await save_navigation_context(callback_data = callback_data, state = kwargs["state"])
callback_data: ContextData = kwargs["callback_data"]
state: FSMContext = kwargs["state"]
state_data = await state.get_data()
kwargs["state_data"] = state_data
clear_state(state_data = state_data)
stack = save_navigation_context(callback_data = callback_data, state_data = state_data)
await entity_item(query = query, callback_data = callback_data, navigation_stack = stack, **kwargs)
await entity_item(query = query, navigation_stack = stack, **kwargs)
async def entity_item(query: CallbackQuery,
callback_data: ContextData,
db_session: AsyncSession,
user: UserBase,
app: QBotApp,
app: "QBotApp",
navigation_stack: list[ContextData],
**kwargs):
@@ -77,8 +84,40 @@ async def entity_item(query: CallbackQuery,
(EntityPermission.DELETE in user_permissions and is_owned and
entity_item.user_id == user.id))
edit_delete_row = []
if can_edit:
for edit_buttons_row in entity_descriptor.edit_buttons:
btn_row = []
for field_name in edit_buttons_row:
field_name, btn_caption = field_name if isinstance(field_name, tuple) else (field_name, None)
if field_name in entity_descriptor.fields_descriptors:
field_descriptor = entity_descriptor.fields_descriptors[field_name]
# if field_descriptor.is_list and issubclass(field_descriptor.type_base, BotEntity):
# await field_descriptor.type_base.
field_value = getattr(entity_item, field_descriptor.field_name)
if btn_caption:
btn_text = get_callable_str(btn_caption, field_descriptor, entity_item, field_value)
else:
if field_descriptor.type_base == bool:
btn_text = f"{"【✔︎】 " if field_value else "【 】 "}{
get_callable_str(field_descriptor.caption, field_descriptor, entity_item, field_value) if field_descriptor.caption
else field_name}"
else:
btn_text = (f"✏️ {get_callable_str(field_descriptor.caption, field_descriptor, entity_item, field_value)}"
if field_descriptor.caption else f"✏️ {field_name}")
btn_row.append(
InlineKeyboardButton(
text = btn_text,
callback_data = ContextData(
command = CallbackCommand.FIELD_EDITOR,
context = CommandContext.ENTITY_FIELD_EDIT,
entity_name = entity_descriptor.name,
entity_id = str(entity_item.id),
field_name = field_name).pack()))
if btn_row:
keyboard_builder.row(*btn_row)
edit_delete_row = []
if can_edit and entity_descriptor.edit_button_visible:
edit_delete_row.append(
InlineKeyboardButton(
text = (await Settings.get(Settings.APP_STRINGS_EDIT_BTN)),
@@ -87,8 +126,7 @@ async def entity_item(query: CallbackQuery,
context = CommandContext.ENTITY_EDIT,
entity_name = entity_descriptor.name,
entity_id = str(entity_item.id),
field_name = entity_descriptor.field_sequence[0],
save_state = True).pack()))
field_name = entity_descriptor.field_sequence[0]).pack()))
if can_delete:
edit_delete_row.append(
@@ -102,15 +140,15 @@ async def entity_item(query: CallbackQuery,
if edit_delete_row:
keyboard_builder.row(*edit_delete_row)
entity_caption = get_callable_str(entity_descriptor.caption_msg, entity_descriptor, entity_item)
entity_caption = get_callable_str(entity_descriptor.caption, entity_descriptor, entity_item)
entity_item_name = get_local_text(entity_item.name, user.lang) if entity_descriptor.fields_descriptors["name"].localizable else entity_item.name
item_text = f"<b><u><i>{entity_caption or entity_descriptor.name}:</i></u></b> <b>{entity_item_name}</b>"
for field_descriptor in entity_descriptor.fields_descriptors.values():
if field_descriptor.name in ["name", "id"] or not field_descriptor.is_visible:
if field_descriptor.name == "name" or not field_descriptor.is_visible:
continue
field_caption = get_callable_str(field_descriptor.caption_str, field_descriptor, entity_item)
field_caption = get_callable_str(field_descriptor.caption, field_descriptor, entity_item)
value = get_value_repr(value = getattr(entity_item, field_descriptor.name),
field_descriptor = field_descriptor,
locale = user.lang)
@@ -123,6 +161,10 @@ async def entity_item(query: CallbackQuery,
text = (await Settings.get(Settings.APP_STRINGS_BACK_BTN)),
callback_data = context.pack()))
state: FSMContext = kwargs["state"]
state_data = kwargs["state_data"]
await state.set_data(state_data)
send_message = get_send_message(query)
await send_message(text = item_text, reply_markup = keyboard_builder.as_markup())
@@ -134,7 +176,7 @@ async def entity_delete_callback(query: CallbackQuery, **kwargs):
callback_data: ContextData = kwargs["callback_data"]
user: UserBase = kwargs["user"]
db_session: AsyncSession = kwargs["db_session"]
app: QBotApp = kwargs["app"]
app: "QBotApp" = kwargs["app"]
entity_descriptor = get_entity_descriptor(app = app, callback_data = callback_data)
user_permissions = get_user_permissions(user, entity_descriptor)
@@ -147,8 +189,18 @@ async def entity_delete_callback(query: CallbackQuery, **kwargs):
entity.user_id == user.id)):
return await query.answer(text = (await Settings.get(Settings.APP_STRINGS_FORBIDDEN)))
if callback_data.data == "yes":
if not callback_data.data:
await entity_descriptor.type_.remove(
session = db_session, id = int(callback_data.entity_id), commit = True)
await route_callback(message = query, **kwargs)
elif callback_data.data == "no":
await route_callback(message = query, back = False, **kwargs)
elif not callback_data.data:
field_descriptor = entity_descriptor.fields_descriptors["name"]
@@ -175,16 +227,6 @@ async def entity_delete_callback(query: CallbackQuery, **kwargs):
entity_name = callback_data.entity_name,
entity_id = callback_data.entity_id,
data = "no").pack())).as_markup())
if callback_data.data == "yes":
await entity_descriptor.type_.remove(
session = db_session, id = int(callback_data.entity_id), commit = True)
await route_callback(message = query, **kwargs)
if callback_data.data == "no":
await route_callback(message = query, back = False, **kwargs)

View File

@@ -1,4 +1,4 @@
from typing import get_args, get_origin
from typing import get_args, get_origin, TYPE_CHECKING
from aiogram import Router, F
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
@@ -9,18 +9,21 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
from logging import getLogger
from sqlmodel.ext.asyncio.session import AsyncSession
from ....main import QBotApp
from ....model.bot_entity import BotEntity
from ....model.bot_enum import BotEnum
from ....model.owned_bot_entity import OwnedBotEntity
from ....model.settings import Settings
from ....model.user import UserBase
from ....model.view_setting import ViewSetting
from ....model.descriptors import EntityFieldDescriptor, EntityDescriptor
from ....model import EntityPermission
from ....utils import serialize, deserialize, get_user_permissions
from ..context import ContextData, CallbackCommand, CommandContext
from ..common import (add_pagination_controls, get_local_text, get_entity_descriptor,
get_callable_str, get_send_message)
get_callable_str, get_send_message, add_filter_controls)
if TYPE_CHECKING:
from ....main import QBotApp
logger = getLogger(__name__)
@@ -28,22 +31,28 @@ router = Router()
@router.callback_query(ContextData.filter(F.command == CallbackCommand.ENTITY_LIST))
async def entity_list_callback(query: CallbackQuery, callback_data: ContextData, **kwargs):
async def entity_list_callback(query: CallbackQuery, **kwargs):
callback_data: ContextData = kwargs["callback_data"]
if callback_data.data == "skip":
return
await clear_state(state = kwargs["state"])
stack = await save_navigation_context(callback_data = callback_data, state = kwargs["state"])
await entity_list(message = query, callback_data = callback_data, navigation_stack = stack, **kwargs)
state: FSMContext = kwargs["state"]
state_data = await state.get_data()
kwargs["state_data"] = state_data
clear_state(state_data = state_data)
stack = save_navigation_context(callback_data = callback_data, state_data = state_data)
await entity_list(message = query, navigation_stack = stack, **kwargs)
async def entity_list(message: CallbackQuery | Message,
callback_data: ContextData,
db_session: AsyncSession,
user: UserBase,
app: QBotApp,
app: "QBotApp",
navigation_stack: list[ContextData],
**kwargs):
@@ -68,38 +77,54 @@ async def entity_list(message: CallbackQuery | Message,
page_size = await Settings.get(Settings.PAGE_SIZE)
entity_filter = await ViewSetting.get_filter(session = db_session, user_id = user.id, entity_name = entity_descriptor.class_name)
def calc_total_pages(items_count: int, page_size: int) -> int:
return max(items_count // page_size + (1 if items_count % page_size else 0), 1)
if issubclass(entity_type, OwnedBotEntity):
if EntityPermission.READ_ALL in user_permissions or EntityPermission.LIST_ALL in user_permissions:
items_count = await entity_type.get_count(session = db_session, filter = entity_filter)
total_pages = calc_total_pages(items_count, page_size)
page = min(page, total_pages)
items = await entity_type.get_multi(
session = db_session, order_by = entity_type.name,
skip = page_size * (page - 1), limit = page_size)
items_count = await entity_type.get_count(session = db_session)
session = db_session, order_by = entity_type.name, filter = entity_filter,
skip = page_size * (page - 1), limit = page_size)
elif EntityPermission.READ in user_permissions or EntityPermission.LIST in user_permissions:
items_count = await entity_type.get_count_by_user(session = db_session, user_id = user.id, filter = entity_filter)
total_pages = calc_total_pages(items_count, page_size)
page = min(page, total_pages)
items = await entity_type.get_multi_by_user(
session = db_session, user_id = user.id, order_by = entity_type.name,
session = db_session, user_id = user.id, order_by = entity_type.name, filter = entity_filter,
skip = page_size * (page - 1), limit = page_size)
items_count = await entity_type.get_count_by_user(session = db_session, user_id = user.id)
else:
items = list[OwnedBotEntity]()
items_count = 0
total_pages = 1
page = 1
elif issubclass(entity_type, BotEntity):
if (EntityPermission.READ in user_permissions or EntityPermission.LIST in user_permissions or
EntityPermission.READ_ALL in user_permissions or EntityPermission.LIST_ALL in user_permissions):
items_count = await entity_type.get_count(session = db_session, filter = entity_filter)
total_pages = calc_total_pages(items_count, page_size)
page = min(page, total_pages)
items = await entity_type.get_multi(
session = db_session, order_by = entity_type.name,
session = db_session, order_by = entity_type.name, filter = entity_filter,
skip = page_size * (page - 1), limit = page_size)
items_count = await entity_type.get_count(session = db_session)
else:
items = list[BotEntity]()
total_pages = 1
page = 1
items_count = 0
else:
raise ValueError(f"Unsupported entity type: {entity_type}")
total_pages = items_count // page_size + (1 if items_count % page_size else 0)
for item in items:
if entity_descriptor.item_caption_btn:
caption = entity_descriptor.item_caption_btn(entity_descriptor, item)
if entity_descriptor.item_caption:
caption = entity_descriptor.item_caption(entity_descriptor, item)
elif entity_descriptor.fields_descriptors["name"].localizable:
caption = get_local_text(item.name, user.lang)
else:
@@ -118,6 +143,10 @@ async def entity_list(message: CallbackQuery | Message,
command = CallbackCommand.ENTITY_LIST,
page = page)
add_filter_controls(keyboard_builder = keyboard_builder,
entity_descriptor = entity_descriptor,
filter = entity_filter)
context = pop_navigation_context(navigation_stack)
if context:
keyboard_builder.row(
@@ -125,8 +154,8 @@ async def entity_list(message: CallbackQuery | Message,
text = (await Settings.get(Settings.APP_STRINGS_BACK_BTN)),
callback_data = context.pack()))
if entity_descriptor.caption_msg:
entity_text = get_callable_str(entity_descriptor.caption_msg, entity_descriptor)
if entity_descriptor.caption:
entity_text = get_callable_str(entity_descriptor.caption_plural, entity_descriptor)
else:
entity_text = entity_descriptor.name
if entity_descriptor.description:
@@ -134,6 +163,10 @@ async def entity_list(message: CallbackQuery | Message,
else:
entity_desciption = None
state: FSMContext = kwargs["state"]
state_data = kwargs["state_data"]
await state.set_data(state_data)
send_message = get_send_message(message)
await send_message(text = f"{entity_text}{f"\n{entity_desciption}" if entity_desciption else ""}",