add ruff format, ruff check, time_picker, project structure and imports reorganized
This commit is contained in:
@@ -1,24 +1,28 @@
|
||||
from typing import get_args, get_origin, TYPE_CHECKING
|
||||
from typing import 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.types import CallbackQuery, InlineKeyboardButton
|
||||
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.descriptors import FieldEditButton, CommandButton
|
||||
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 ....utils.main import (
|
||||
check_entity_permission,
|
||||
get_send_message,
|
||||
clear_state,
|
||||
get_value_repr,
|
||||
get_callable_str,
|
||||
get_entity_descriptor,
|
||||
)
|
||||
from ..context import ContextData, CallbackCommand, CommandContext
|
||||
from ..common import get_send_message, get_local_text, get_entity_descriptor, get_callable_str, get_value_repr
|
||||
from ..navigation import (
|
||||
pop_navigation_context,
|
||||
save_navigation_context,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ....main import QBotApp
|
||||
@@ -30,204 +34,212 @@ 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)
|
||||
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):
|
||||
|
||||
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_
|
||||
# user_permissions = get_user_permissions(user, entity_descriptor)
|
||||
entity_type = entity_descriptor.type_
|
||||
|
||||
keyboard_builder = InlineKeyboardBuilder()
|
||||
|
||||
entity_item = await entity_type.get(session = db_session, id = callback_data.entity_id)
|
||||
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)))
|
||||
return await query.answer(
|
||||
text=(await Settings.get(Settings.APP_STRINGS_NOT_FOUND))
|
||||
)
|
||||
|
||||
is_owned = issubclass(entity_type, OwnedBotEntity)
|
||||
# is_owned = issubclass(entity_type, OwnedBotEntity)
|
||||
|
||||
if (EntityPermission.READ not in user_permissions and
|
||||
EntityPermission.READ_ALL not in user_permissions):
|
||||
if not check_entity_permission(
|
||||
entity=entity_item, user=user, permission=EntityPermission.READ
|
||||
):
|
||||
return await query.answer(
|
||||
text=(await Settings.get(Settings.APP_STRINGS_FORBIDDEN))
|
||||
)
|
||||
|
||||
return await query.answer(text = (await Settings.get(Settings.APP_STRINGS_FORBIDDEN)))
|
||||
can_edit = check_entity_permission(
|
||||
entity=entity_item, user=user, permission=EntityPermission.UPDATE
|
||||
)
|
||||
|
||||
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))
|
||||
form = entity_descriptor.forms.get(
|
||||
callback_data.form_params or "default", entity_descriptor.default_form
|
||||
)
|
||||
|
||||
if can_edit:
|
||||
for edit_buttons_row in entity_descriptor.edit_buttons:
|
||||
for edit_buttons_row in form.form_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}"
|
||||
for button in edit_buttons_row:
|
||||
if isinstance(button, FieldEditButton):
|
||||
field_name = button.field_name
|
||||
btn_caption = button.caption
|
||||
if field_name in entity_descriptor.fields_descriptors:
|
||||
field_descriptor = entity_descriptor.fields_descriptors[
|
||||
field_name
|
||||
]
|
||||
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:
|
||||
btn_text = (f"✏️ {get_callable_str(field_descriptor.caption, field_descriptor, entity_item, field_value)}"
|
||||
if field_descriptor.caption else f"✏️ {field_name}")
|
||||
if field_descriptor.type_base is 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(),
|
||||
)
|
||||
)
|
||||
|
||||
elif isinstance(button, CommandButton):
|
||||
btn_caption = button.caption
|
||||
if btn_caption:
|
||||
btn_text = get_callable_str(
|
||||
btn_caption, entity_descriptor, entity_item
|
||||
)
|
||||
else:
|
||||
btn_text = button.command
|
||||
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()))
|
||||
text=btn_text,
|
||||
callback_data=(
|
||||
button.context_data.pack()
|
||||
if button.context_data
|
||||
else ContextData(
|
||||
command=CallbackCommand.USER_COMMAND,
|
||||
user_command=button.command,
|
||||
data=str(entity_item.id),
|
||||
).pack()
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
if btn_row:
|
||||
keyboard_builder.row(*btn_row)
|
||||
|
||||
edit_delete_row = []
|
||||
if can_edit and entity_descriptor.edit_button_visible:
|
||||
if can_edit and form.show_edit_button:
|
||||
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:
|
||||
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),
|
||||
form_params=callback_data.form_params,
|
||||
field_name=form.edit_field_sequence[0],
|
||||
).pack(),
|
||||
)
|
||||
)
|
||||
|
||||
if (
|
||||
check_entity_permission(
|
||||
entity=entity_item, user=user, permission=EntityPermission.DELETE
|
||||
)
|
||||
and form.show_delete_button
|
||||
):
|
||||
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()))
|
||||
|
||||
text=(await Settings.get(Settings.APP_STRINGS_DELETE_BTN)),
|
||||
callback_data=ContextData(
|
||||
command=CallbackCommand.ENTITY_DELETE,
|
||||
entity_name=entity_descriptor.name,
|
||||
form_params=callback_data.form_params,
|
||||
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
|
||||
if form.item_repr:
|
||||
item_text = form.item_repr(entity_descriptor, entity_item)
|
||||
else:
|
||||
entity_caption = (
|
||||
get_callable_str(
|
||||
entity_descriptor.full_name, entity_descriptor, entity_item
|
||||
)
|
||||
if entity_descriptor.full_name
|
||||
else entity_descriptor.name
|
||||
)
|
||||
|
||||
item_text = f"<b><u><i>{entity_caption or entity_descriptor.name}:</i></u></b> <b>{entity_item_name}</b>"
|
||||
entity_item_repr = (
|
||||
get_callable_str(
|
||||
entity_descriptor.item_repr, entity_descriptor, entity_item
|
||||
)
|
||||
if entity_descriptor.item_repr
|
||||
else str(entity_item.id)
|
||||
)
|
||||
|
||||
item_text = f"<b><u><i>{entity_caption or entity_descriptor.name}:</i></u></b> <b>{entity_item_repr}</b>"
|
||||
|
||||
for field_descriptor in entity_descriptor.fields_descriptors.values():
|
||||
if field_descriptor.is_visible:
|
||||
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 ''}"
|
||||
|
||||
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()))
|
||||
|
||||
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
|
||||
await send_message(text=item_text, reply_markup=keyboard_builder.as_markup())
|
||||
|
||||
Reference in New Issue
Block a user