Unification of pagination, admins control and more

This commit is contained in:
2026-03-02 19:02:20 +07:00
parent 035170e46f
commit eab67ccfc1
13 changed files with 271 additions and 118 deletions

View File

@@ -3,8 +3,11 @@ from typing import Optional, Callable
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
from config import PAGE_SIZE
from db.models import Category, Product
from dto.cart import CartItemDTO
from dto.catalogue import CatalogueView, CatalogueType
from .common import return_menu
def pagination_row(
@@ -59,6 +62,7 @@ def render_category(
show_menu: bool = False,
*,
category_cb_factory: Callable[[Category], str],
is_admin: bool = False,
) -> InlineKeyboardMarkup:
btns = [
InlineKeyboardButton(
@@ -68,18 +72,27 @@ def render_category(
for category in children
]
nav = []
nav: list[list[InlineKeyboardButton]] = []
if parent_id is not None:
if is_admin:
nav.append(
InlineKeyboardButton(text="⬅️ Назад", callback_data=f"cat:{parent_id}")
[
InlineKeyboardButton(
text="📄 Добавить категорию",
callback_data=f"new:category:{parent_id}",
)
]
)
if show_menu:
nav.append(InlineKeyboardButton(text="⬅️ Назад", callback_data="menu:main"))
nav.append([InlineKeyboardButton(text="⬅️ Назад", callback_data="menu:main")])
elif parent_id is not None:
nav.append(
[InlineKeyboardButton(text="⬅️ Назад", callback_data=f"cat:{parent_id}")]
)
return InlineKeyboardBuilder(
[btns[i : i + 2] for i in range(0, len(children), 2)] + [nav],
[btns[i : i + 2] for i in range(0, len(children), 2)] + nav,
).as_markup()
@@ -91,6 +104,8 @@ def render_products(
prev_cb: Optional[str] = None,
next_cb: Optional[str] = None,
columns: int = 2,
is_admin: bool = False,
cat_id: Optional[int] = None,
) -> InlineKeyboardMarkup:
builder = InlineKeyboardBuilder()
@@ -107,6 +122,13 @@ def render_products(
]
builder.row(*row)
if is_admin:
builder.row(
InlineKeyboardButton(
text="📦 Добавить товар", callback_data=f"new:product:{cat_id}"
)
)
nav_buttons = []
if prev_cb:
nav_buttons.append(InlineKeyboardButton(text="◀️", callback_data=prev_cb))
@@ -119,6 +141,32 @@ def render_products(
return builder.as_markup()
def render_catalogue(view: CatalogueView, *, is_admin: bool):
if view.view_type == CatalogueType.CATEGORIES:
return render_category(
children=view.children[:PAGE_SIZE], # type: ignore
parent_id=view.parent_id,
show_menu=view.show_menu,
category_cb_factory=lambda c: f"cat:{c.id}",
is_admin=is_admin,
)
if view.view_type == CatalogueType.PRODUCTS:
return render_products(
products=view.products[:PAGE_SIZE], # type: ignore
product_cb_factory=lambda p: f"product:{p.id}",
back_cb=f"cat:{view.parent_id}",
prev_cb=(
f"products:{view.category}:{view.page - 1}" if view.page > 0 else None
),
next_cb=(
f"products:{view.category}:{view.page + 1}" if view.has_next else None
),
is_admin=is_admin,
)
return return_menu
def render_product_interactions(
*, product_id: int, category_id: int, show_cart: bool = False, cart_amount: int = 0
) -> InlineKeyboardMarkup:

27
misc/redis.py Normal file
View File

@@ -0,0 +1,27 @@
import logging
from typing import Optional
from redis.asyncio import Redis
logger = logging.getLogger(__name__)
class RedisClient:
def __init__(self, r: Redis):
self.r = r
async def set_search_query(self, query_hash: str, q: str, ttl: int = 3600) -> bool:
try:
await self.r.set(f"search:{query_hash}", q, ex=ttl)
return True
except Exception as e:
logger.exception(e)
return False
async def get_search_query(self, query_hash: str) -> Optional[str]:
try:
res = await self.r.get(f"search:{query_hash}")
return res.decode()
except Exception as e:
logger.exception(e)
return None