diff options
| -rw-r--r-- | handlers/user/__init__.py | 2 | ||||
| -rw-r--r-- | handlers/user/announcements.py | 120 | ||||
| -rw-r--r-- | libs/msg.py | 6 | ||||
| -rw-r--r-- | models/callback_data.py | 9 |
4 files changed, 137 insertions, 0 deletions
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 | |||
| 4 | from . import info | 4 | from . import info |
| 5 | from . import vpn_link | 5 | from . import vpn_link |
| 6 | from . import pay_invoice | 6 | from . import pay_invoice |
| 7 | from . import announcements | ||
| 7 | # isort: on | 8 | # isort: on |
| 8 | 9 | ||
| 9 | router = Router(name="user") | 10 | router = Router(name="user") |
| @@ -11,4 +12,5 @@ router.include_routers( | |||
| 11 | info.router, | 12 | info.router, |
| 12 | vpn_link.router, | 13 | vpn_link.router, |
| 13 | pay_invoice.router, | 14 | pay_invoice.router, |
| 15 | announcements.router, | ||
| 14 | ) | 16 | ) |
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 @@ | |||
| 1 | from math import ceil | ||
| 2 | |||
| 3 | from aiogram import Bot, Router | ||
| 4 | from aiogram.filters import Command | ||
| 5 | from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message | ||
| 6 | from aiogram.types.callback_query import CallbackQuery | ||
| 7 | from sqlalchemy import select | ||
| 8 | from sqlalchemy.ext.asyncio import AsyncSession | ||
| 9 | from sqlalchemy.sql.functions import count | ||
| 10 | |||
| 11 | from libs.msg import eclipse_text | ||
| 12 | from models import Announcement | ||
| 13 | from models.callback_data import AnnounceItemClb, AnnouncePageClb | ||
| 14 | |||
| 15 | router = Router(name="announcements") | ||
| 16 | PAGE_SIZE = 5 | ||
| 17 | |||
| 18 | |||
| 19 | async def get_reply_markup(page: int, session: AsyncSession) -> InlineKeyboardMarkup: | ||
| 20 | total = await session.scalar(select(count()).select_from(Announcement)) | ||
| 21 | assert total is not None | ||
| 22 | total_pages = ceil(total / PAGE_SIZE) | ||
| 23 | |||
| 24 | page = max(0, min(page, total_pages - 1)) | ||
| 25 | query = ( | ||
| 26 | select(Announcement) | ||
| 27 | .offset(PAGE_SIZE * page) | ||
| 28 | .limit(PAGE_SIZE) | ||
| 29 | .order_by(Announcement.id.desc()) | ||
| 30 | ) | ||
| 31 | announcements = await session.scalars(query) | ||
| 32 | |||
| 33 | announcement_buttons = [ | ||
| 34 | [ | ||
| 35 | InlineKeyboardButton( | ||
| 36 | text=( | ||
| 37 | f"{eclipse_text(a.message.text, 10)} " | ||
| 38 | f"({a.datetime.strftime('%d %b %y г.')})" | ||
| 39 | ), | ||
| 40 | callback_data=AnnounceItemClb(page=page, announce_id=a.id).pack(), | ||
| 41 | ) | ||
| 42 | ] | ||
| 43 | for a in announcements | ||
| 44 | ] | ||
| 45 | |||
| 46 | page_buttons = [] | ||
| 47 | if page > 0: | ||
| 48 | page_buttons.append( | ||
| 49 | InlineKeyboardButton( | ||
| 50 | text="◀️", | ||
| 51 | callback_data=AnnouncePageClb(page=page - 1).pack(), | ||
| 52 | ) | ||
| 53 | ) | ||
| 54 | if page < total_pages - 1: | ||
| 55 | page_buttons.append( | ||
| 56 | InlineKeyboardButton( | ||
| 57 | text="▶️", | ||
| 58 | callback_data=AnnouncePageClb(page=page + 1).pack(), | ||
| 59 | ) | ||
| 60 | ) | ||
| 61 | |||
| 62 | return InlineKeyboardMarkup(inline_keyboard=[*announcement_buttons, page_buttons]) | ||
| 63 | |||
| 64 | |||
| 65 | @router.message(Command("announcements")) | ||
| 66 | async def command(msg: Message, bot: Bot, session: AsyncSession) -> None: | ||
| 67 | await msg.answer( | ||
| 68 | "Выберете анонс для просмотра.", | ||
| 69 | reply_markup=await get_reply_markup(0, session), | ||
| 70 | ) | ||
| 71 | |||
| 72 | |||
| 73 | @router.callback_query(AnnouncePageClb.filter()) | ||
| 74 | async def page( | ||
| 75 | clb: CallbackQuery, | ||
| 76 | callback_data: AnnouncePageClb, | ||
| 77 | session: AsyncSession, | ||
| 78 | ) -> None: | ||
| 79 | assert isinstance(clb.message, Message) | ||
| 80 | |||
| 81 | reply_markup = await get_reply_markup(callback_data.page, session) | ||
| 82 | await clb.message.edit_text( | ||
| 83 | "Выберете анонс для просмотра.", | ||
| 84 | reply_markup=reply_markup, | ||
| 85 | ) | ||
| 86 | |||
| 87 | await clb.answer() | ||
| 88 | |||
| 89 | |||
| 90 | @router.callback_query(AnnounceItemClb.filter()) | ||
| 91 | async def item( | ||
| 92 | clb: CallbackQuery, | ||
| 93 | callback_data: AnnounceItemClb, | ||
| 94 | session: AsyncSession, | ||
| 95 | ) -> None: | ||
| 96 | assert isinstance(clb.message, Message) | ||
| 97 | |||
| 98 | announcement = await session.get(Announcement, callback_data.announce_id) | ||
| 99 | assert announcement is not None | ||
| 100 | |||
| 101 | rich_text = announcement.message | ||
| 102 | reply_markup = InlineKeyboardMarkup( | ||
| 103 | inline_keyboard=[ | ||
| 104 | [ | ||
| 105 | InlineKeyboardButton( | ||
| 106 | text="Назад к выбору", | ||
| 107 | callback_data=AnnouncePageClb(page=callback_data.page).pack(), | ||
| 108 | ) | ||
| 109 | ] | ||
| 110 | ] | ||
| 111 | ) | ||
| 112 | |||
| 113 | await clb.message.edit_text( | ||
| 114 | text=rich_text.text, | ||
| 115 | entities=rich_text.entities, | ||
| 116 | parse_mode=None, | ||
| 117 | reply_markup=reply_markup, | ||
| 118 | ) | ||
| 119 | |||
| 120 | await clb.answer() | ||
diff --git a/libs/msg.py b/libs/msg.py index c55e78d..d1c3b08 100644 --- a/libs/msg.py +++ b/libs/msg.py | |||
| @@ -10,6 +10,12 @@ from models import RichText | |||
| 10 | from models.callback_data import PayInvoiceClb | 10 | from models.callback_data import PayInvoiceClb |
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | def eclipse_text(text: str, size: int, eclipses: str = "...") -> str: | ||
| 14 | if len(text) <= size: | ||
| 15 | return text | ||
| 16 | return f"{text[: size - len(eclipses)]}{eclipses}" | ||
| 17 | |||
| 18 | |||
| 13 | async def publish_announcement( | 19 | async def publish_announcement( |
| 14 | bot: Bot, | 20 | bot: Bot, |
| 15 | users: Iterable[int], | 21 | users: Iterable[int], |
diff --git a/models/callback_data.py b/models/callback_data.py index 137c4fa..4d37226 100644 --- a/models/callback_data.py +++ b/models/callback_data.py | |||
| @@ -10,3 +10,12 @@ class PayInvoiceClb(CallbackData, prefix="pay_invoice"): | |||
| 10 | class PaymentStatusClb(CallbackData, prefix="payment_status"): | 10 | class PaymentStatusClb(CallbackData, prefix="payment_status"): |
| 11 | payment_id: int | 11 | payment_id: int |
| 12 | payment_status: PaymentStatus | 12 | payment_status: PaymentStatus |
| 13 | |||
| 14 | |||
| 15 | class AnnouncePageClb(CallbackData, prefix="a10t.p"): | ||
| 16 | page: int | ||
| 17 | |||
| 18 | |||
| 19 | class AnnounceItemClb(CallbackData, prefix="a10t.i"): | ||
| 20 | page: int | ||
| 21 | announce_id: int | ||
