From 4d0f8a48502dfa6bc7e9b39444573fe7377bdfce Mon Sep 17 00:00:00 2001 From: Tolmachev Igor Date: Wed, 25 Mar 2026 14:56:02 +0300 Subject: Add announcements --- handlers/user/__init__.py | 2 + handlers/user/announcements.py | 120 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 handlers/user/announcements.py (limited to 'handlers') diff --git a/handlers/user/__init__.py b/handlers/user/__init__.py index 4b43427..a0e719f 100644 --- a/handlers/user/__init__.py +++ b/handlers/user/__init__.py @@ -4,6 +4,7 @@ from aiogram import Router from . import info from . import vpn_link from . import pay_invoice +from . import announcements # isort: on router = Router(name="user") @@ -11,4 +12,5 @@ router.include_routers( info.router, vpn_link.router, pay_invoice.router, + announcements.router, ) diff --git a/handlers/user/announcements.py b/handlers/user/announcements.py new file mode 100644 index 0000000..8f4aa43 --- /dev/null +++ b/handlers/user/announcements.py @@ -0,0 +1,120 @@ +from math import ceil + +from aiogram import Bot, Router +from aiogram.filters import Command +from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message +from aiogram.types.callback_query import CallbackQuery +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.sql.functions import count + +from libs.msg import eclipse_text +from models import Announcement +from models.callback_data import AnnounceItemClb, AnnouncePageClb + +router = Router(name="announcements") +PAGE_SIZE = 5 + + +async def get_reply_markup(page: int, session: AsyncSession) -> InlineKeyboardMarkup: + total = await session.scalar(select(count()).select_from(Announcement)) + assert total is not None + total_pages = ceil(total / PAGE_SIZE) + + page = max(0, min(page, total_pages - 1)) + query = ( + select(Announcement) + .offset(PAGE_SIZE * page) + .limit(PAGE_SIZE) + .order_by(Announcement.id.desc()) + ) + announcements = await session.scalars(query) + + announcement_buttons = [ + [ + InlineKeyboardButton( + text=( + f"{eclipse_text(a.message.text, 10)} " + f"({a.datetime.strftime('%d %b %y г.')})" + ), + callback_data=AnnounceItemClb(page=page, announce_id=a.id).pack(), + ) + ] + for a in announcements + ] + + page_buttons = [] + if page > 0: + page_buttons.append( + InlineKeyboardButton( + text="◀️", + callback_data=AnnouncePageClb(page=page - 1).pack(), + ) + ) + if page < total_pages - 1: + page_buttons.append( + InlineKeyboardButton( + text="▶️", + callback_data=AnnouncePageClb(page=page + 1).pack(), + ) + ) + + return InlineKeyboardMarkup(inline_keyboard=[*announcement_buttons, page_buttons]) + + +@router.message(Command("announcements")) +async def command(msg: Message, bot: Bot, session: AsyncSession) -> None: + await msg.answer( + "Выберете анонс для просмотра.", + reply_markup=await get_reply_markup(0, session), + ) + + +@router.callback_query(AnnouncePageClb.filter()) +async def page( + clb: CallbackQuery, + callback_data: AnnouncePageClb, + session: AsyncSession, +) -> None: + assert isinstance(clb.message, Message) + + reply_markup = await get_reply_markup(callback_data.page, session) + await clb.message.edit_text( + "Выберете анонс для просмотра.", + reply_markup=reply_markup, + ) + + await clb.answer() + + +@router.callback_query(AnnounceItemClb.filter()) +async def item( + clb: CallbackQuery, + callback_data: AnnounceItemClb, + session: AsyncSession, +) -> None: + assert isinstance(clb.message, Message) + + announcement = await session.get(Announcement, callback_data.announce_id) + assert announcement is not None + + rich_text = announcement.message + reply_markup = InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="Назад к выбору", + callback_data=AnnouncePageClb(page=callback_data.page).pack(), + ) + ] + ] + ) + + await clb.message.edit_text( + text=rich_text.text, + entities=rich_text.entities, + parse_mode=None, + reply_markup=reply_markup, + ) + + await clb.answer() -- cgit v1.3