234 lines
11 KiB
Python
234 lines
11 KiB
Python
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
|
|
from aiogram.fsm.state import StatesGroup, State
|
|
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton
|
|
from aiogram.utils.i18n import I18n
|
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
from logging import getLogger
|
|
from sqlmodel.ext.asyncio.session import AsyncSession
|
|
|
|
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.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 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, **kwargs):
|
|
|
|
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, navigation_stack = stack, **kwargs)
|
|
|
|
|
|
async def entity_item(query: CallbackQuery,
|
|
callback_data: ContextData,
|
|
db_session: AsyncSession,
|
|
user: UserBase,
|
|
app: "QBotApp",
|
|
navigation_stack: list[ContextData],
|
|
**kwargs):
|
|
|
|
entity_descriptor = get_entity_descriptor(app, callback_data)
|
|
user_permissions = get_user_permissions(user, entity_descriptor)
|
|
entity_type: BotEntity = entity_descriptor.type_
|
|
|
|
keyboard_builder = InlineKeyboardBuilder()
|
|
|
|
entity_item = await entity_type.get(session = db_session, id = callback_data.entity_id)
|
|
|
|
if not entity_item:
|
|
return await query.answer(text = (await Settings.get(Settings.APP_STRINGS_NOT_FOUND)))
|
|
|
|
is_owned = issubclass(entity_type, OwnedBotEntity)
|
|
|
|
if (EntityPermission.READ not in user_permissions and
|
|
EntityPermission.READ_ALL not in user_permissions):
|
|
|
|
return await query.answer(text = (await Settings.get(Settings.APP_STRINGS_FORBIDDEN)))
|
|
|
|
if (is_owned and
|
|
EntityPermission.READ_ALL not in user_permissions and
|
|
entity_item.user_id != user.id):
|
|
|
|
return await query.answer(text = (await Settings.get(Settings.APP_STRINGS_FORBIDDEN)))
|
|
|
|
can_edit = (EntityPermission.UPDATE_ALL in user_permissions or
|
|
(EntityPermission.UPDATE in user_permissions and not is_owned) or
|
|
(EntityPermission.UPDATE in user_permissions and is_owned and
|
|
entity_item.user_id == user.id))
|
|
|
|
can_delete = (EntityPermission.DELETE_ALL in user_permissions or
|
|
(EntityPermission.DELETE in user_permissions and not is_owned) or
|
|
(EntityPermission.DELETE in user_permissions and is_owned and
|
|
entity_item.user_id == user.id))
|
|
|
|
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)),
|
|
callback_data = ContextData(
|
|
command = CallbackCommand.FIELD_EDITOR,
|
|
context = CommandContext.ENTITY_EDIT,
|
|
entity_name = entity_descriptor.name,
|
|
entity_id = str(entity_item.id),
|
|
field_name = entity_descriptor.field_sequence[0]).pack()))
|
|
|
|
if can_delete:
|
|
edit_delete_row.append(
|
|
InlineKeyboardButton(
|
|
text = (await Settings.get(Settings.APP_STRINGS_DELETE_BTN)),
|
|
callback_data = ContextData(
|
|
command = CallbackCommand.ENTITY_DELETE,
|
|
entity_name = entity_descriptor.name,
|
|
entity_id = str(entity_item.id)).pack()))
|
|
|
|
if edit_delete_row:
|
|
keyboard_builder.row(*edit_delete_row)
|
|
|
|
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 == "name" or not field_descriptor.is_visible:
|
|
continue
|
|
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)
|
|
item_text += f"\n{field_caption or field_descriptor.name}:{f" <b>{value}</b>" if value else ""}"
|
|
|
|
context = pop_navigation_context(navigation_stack)
|
|
if context:
|
|
keyboard_builder.row(
|
|
InlineKeyboardButton(
|
|
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())
|
|
|
|
|
|
@router.callback_query(ContextData.filter(F.command == CallbackCommand.ENTITY_DELETE))
|
|
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"]
|
|
|
|
entity_descriptor = get_entity_descriptor(app = app, callback_data = callback_data)
|
|
user_permissions = get_user_permissions(user, entity_descriptor)
|
|
|
|
entity = await entity_descriptor.type_.get(session = db_session, id = int(callback_data.entity_id))
|
|
|
|
if not (EntityPermission.DELETE_ALL in user_permissions or
|
|
(EntityPermission.DELETE in user_permissions and not issubclass(entity_descriptor.type_, OwnedBotEntity)) or
|
|
(EntityPermission.DELETE in user_permissions and issubclass(entity_descriptor.type_, OwnedBotEntity) and
|
|
entity.user_id == user.id)):
|
|
|
|
return await query.answer(text = (await Settings.get(Settings.APP_STRINGS_FORBIDDEN)))
|
|
|
|
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)
|
|
|
|
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"]
|
|
|
|
entity = await entity_descriptor.type_.get(session = db_session, id = int(callback_data.entity_id))
|
|
|
|
return await query.message.edit_text(
|
|
text = (await Settings.get(Settings.APP_STRINGS_CONFIRM_DELETE_P_NAME)).format(
|
|
name = get_value_repr(
|
|
value = getattr(entity, field_descriptor.name),
|
|
field_descriptor = field_descriptor,
|
|
locale = user.lang)),
|
|
reply_markup = InlineKeyboardBuilder().row(
|
|
InlineKeyboardButton(
|
|
text = (await Settings.get(Settings.APP_STRINGS_YES_BTN)),
|
|
callback_data = ContextData(
|
|
command = CallbackCommand.ENTITY_DELETE,
|
|
entity_name = callback_data.entity_name,
|
|
entity_id = callback_data.entity_id,
|
|
data = "yes").pack()),
|
|
InlineKeyboardButton(
|
|
text = (await Settings.get(Settings.APP_STRINGS_NO_BTN)),
|
|
callback_data = ContextData(
|
|
command = CallbackCommand.ENTITY_ITEM,
|
|
entity_name = callback_data.entity_name,
|
|
entity_id = callback_data.entity_id,
|
|
data = "no").pack())).as_markup())
|
|
|
|
|
|
|
|
from ..navigation import pop_navigation_context, save_navigation_context, clear_state, route_callback
|