Fix bugs, add README and Makefile

This commit is contained in:
2026-01-16 20:39:51 +03:00
parent 3e515c66ec
commit a065c6b7be
30 changed files with 695 additions and 286 deletions

View File

@@ -6,6 +6,8 @@ from .settings import TelegramBotSettings
__all__ = (
# cli
"get_cli",
# fabric
"get_telegram_bot_service",
# settings
"TelegramBotSettings",
)

View File

@@ -3,6 +3,7 @@ import facet
from aiogram.fsm.storage.memory import MemoryStorage
from birthday_pool_bot.repositories import RepositoriesContainer
from .settings import TelegramBotSettings
from .ui import setup_dispatcher

View File

@@ -12,15 +12,15 @@ def get_telegram_bot_service(
repositories_container: RepositoriesContainer,
) -> BaseTelegramBotService:
match settings.method:
case TelegramBotMethodEnum.POLLING:
case TelegramBotMethodEnum.POLLING.value:
return TelegramBotPollingService(
settings=settings,
repositories_container=repositories_container,
)
case TelegramBotMethodEnum.WEBHOOK:
case TelegramBotMethodEnum.WEBHOOK.value:
return TelegramBotWebhookService(
settings=settings,
repositories_container=repositories_container,
)
case _:
raise ValueError(f"Cannot create telegram bot with method '{settings.method.value}'")
raise ValueError(f"Cannot create telegram bot with method '{settings.method}'")

View File

@@ -3,6 +3,7 @@ from birthday_pool_bot.telegram_bot.base import BaseTelegramBotService
class TelegramBotPollingService(BaseTelegramBotService):
async def listen_events(self):
await self._bot.delete_webhook()
await self._dispatcher._polling( # pylint: disable=protected-access
bot=self._bot,
polling_timeout=self._settings.timeout,

View File

@@ -8,7 +8,7 @@ from birthday_pool_bot.telegram_bot.settings import TelegramBotSettings
class TelegramBotPollingSettings(TelegramBotSettings):
method: Literal[TelegramBotMethodEnum.POLLING.value] = (
TelegramBotMethodEnum.POLLING
TelegramBotMethodEnum.POLLING.value
)
timeout: PositiveInt = 10 # in seconds

View File

@@ -1,9 +1,7 @@
import enum
import uuid
from typing import Any
from aiogram.filters.callback_data import CallbackData
from pydantic import Field
class PaginatorCallbackData(CallbackData, prefix=""):
@@ -18,7 +16,7 @@ class SubscriptionsCallbackData(PaginatorCallbackData, prefix="subscriptions"):
pass
class AddSubscriptionCallbackData(CallbackData, prefix="subscription_add"):
class NewSubscriptionCallbackData(CallbackData, prefix="new_subscription"):
pass
@@ -27,7 +25,7 @@ class ConfirmAnswerEnum(str, enum.Enum):
NO = "no"
class AddSubscriptionConfirmCallbackData(CallbackData, prefix="subscription_add_confirm"):
class NewSubscriptionConfirmCallbackData(CallbackData, prefix="new_subscription_confirm"):
answer: ConfirmAnswerEnum
@@ -43,5 +41,19 @@ class SubscriptionCallbackData(CallbackData, prefix="subscription"):
action: SubscriptionActionEnum = SubscriptionActionEnum.SHOW
class AddSubscriptionPoolsCallbackData(PaginatorCallbackData, prefix="subscription_add_pool"):
to_user_id: uuid.UUID
class PoolsCallbackData(PaginatorCallbackData, prefix="pools"):
pass
class PoolsBackCallbackData(CallbackData, prefix="pools_back"):
pass
class PoolActionEnum(str, enum.Enum):
SHOW = "show"
CHOOSE = "choose"
class PoolCallbackData(CallbackData, prefix="pool"):
id: uuid.UUID
action: PoolActionEnum = PoolActionEnum.SHOW

View File

@@ -1,14 +1,17 @@
import aiogram
from aiogram.filters import Command
from aiogram_dialog import DialogManager
from birthday_pool_bot.repositories import RepositoriesContainer
from . import constants, handlers
from .callback_data import (
AddSubscriptionCallbackData,
AddSubscriptionConfirmCallbackData,
ConfirmAnswerEnum,
MenuCallbackData,
NewSubscriptionCallbackData,
NewSubscriptionConfirmCallbackData,
PoolActionEnum,
PoolCallbackData,
PoolsBackCallbackData,
PoolsCallbackData,
SubscriptionActionEnum,
SubscriptionCallbackData,
SubscriptionsCallbackData,
@@ -16,12 +19,12 @@ from .callback_data import (
from .middlewares import (
AuthMiddleware,
DependsMiddleware,
TypingMiddleware,
# TypingMiddleware,
)
from .states import (
AddSubscriptionPoolState,
AddSubscriptionState,
MenuState,
NewSubscriptionPoolState,
NewSubscriptionState,
SetProfileBirthdayState,
SetProfileGiftPaymentDataState,
SetProfileNameState,
@@ -33,7 +36,7 @@ def setup_dispatcher(
dispatcher: aiogram.Dispatcher,
repositories_container: RepositoriesContainer,
):
typing_middleware = TypingMiddleware()
# typing_middleware = TypingMiddleware()
auth_middleware = AuthMiddleware(users_repository=repositories_container.users)
users_repository_middleware = DependsMiddleware(
name="users_repository",
@@ -175,9 +178,9 @@ def setup_router(router: aiogram.Router) -> aiogram.Router:
SubscriptionsCallbackData.filter(),
)
router.callback_query.register(
handlers.add_subscription_callback_handler,
handlers.new_subscription_callback_handler,
MenuState.SUBSCRIPTIONS,
AddSubscriptionCallbackData.filter(),
NewSubscriptionCallbackData.filter(),
)
router.callback_query.register(
handlers.menu_callback_handler,
@@ -203,107 +206,132 @@ def setup_router(router: aiogram.Router) -> aiogram.Router:
### Add new subscription
router.message.register(
handlers.add_subscription_message_handler,
AddSubscriptionState.WAITING_FOR_PHONE,
handlers.new_subscription_message_handler,
NewSubscriptionState.WAITING_FOR_PHONE,
aiogram.F.text == constants.BACK_BUTTON,
)
router.message.register(
handlers.set_add_subscription_user_message_handler,
AddSubscriptionState.WAITING_FOR_PHONE,
handlers.set_new_subscription_user_message_handler,
NewSubscriptionState.WAITING_FOR_PHONE,
)
router.message.register(
handlers.ask_add_subscription_user_message_handler,
AddSubscriptionState.WAITING_FOR_DATE,
handlers.ask_new_subscription_user_message_handler,
NewSubscriptionState.WAITING_FOR_DATE,
aiogram.F.text == constants.BACK_BUTTON,
)
router.message.register(
handlers.set_add_subscription_user_birthday_message_handler,
AddSubscriptionState.WAITING_FOR_DATE,
handlers.set_new_subscription_user_birthday_message_handler,
NewSubscriptionState.WAITING_FOR_DATE,
)
router.message.register(
handlers.ask_add_subscription_user_message_handler,
AddSubscriptionState.WAITING_FOR_NAME,
handlers.ask_new_subscription_user_message_handler,
NewSubscriptionState.WAITING_FOR_NAME,
aiogram.F.text == constants.BACK_BUTTON,
)
router.message.register(
handlers.set_add_subscription_name_message_handler,
AddSubscriptionState.WAITING_FOR_NAME,
handlers.set_new_subscription_name_message_handler,
NewSubscriptionState.WAITING_FOR_NAME,
)
router.message.register(
handlers.ask_add_subscription_pool_description_message_handler,
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
handlers.ask_new_subscription_pool_description_message_handler,
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
aiogram.F.text == constants.CREATE_POOL_BUTTON,
)
router.message.register(
handlers.show_add_subscription_pools_message_handler,
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
handlers.show_new_subscription_choosing_pools_message_handler,
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
aiogram.F.text == constants.JOIN_EXISTING_POOL_BUTTON,
)
router.message.register(
handlers.ask_add_subscription_confirmation_message_handler,
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
handlers.ask_new_subscription_confirmation_message_handler,
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
aiogram.F.text == constants.DECLINE_POOL_BUTTON,
)
router.message.register(
handlers.ask_add_subscription_name_message_handler,
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
handlers.ask_new_subscription_name_message_handler,
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
aiogram.F.text == constants.BACK_BUTTON,
)
router.callback_query.register(
handlers.confirm_add_subscription_callback_handler,
AddSubscriptionState.WAITING_FOR_CONFIRMATION,
AddSubscriptionConfirmCallbackData.filter(
handlers.confirm_new_subscription_callback_handler,
NewSubscriptionState.WAITING_FOR_CONFIRMATION,
NewSubscriptionConfirmCallbackData.filter(
aiogram.F.answer == ConfirmAnswerEnum.YES,
),
)
router.callback_query.register(
handlers.subscriptions_callback_handler,
AddSubscriptionState.WAITING_FOR_CONFIRMATION,
AddSubscriptionConfirmCallbackData.filter(
NewSubscriptionState.WAITING_FOR_CONFIRMATION,
NewSubscriptionConfirmCallbackData.filter(
aiogram.F.answer == ConfirmAnswerEnum.NO,
),
)
#### Add new subscription pool
router.message.register(
handlers.ask_add_subscription_pool_payment_phone_message_handler,
AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
handlers.ask_new_subscription_pool_payment_phone_message_handler,
NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
aiogram.F.text == constants.SKIP_BUTTON,
)
router.message.register(
handlers.ask_add_subscription_pool_decision_message_handler,
AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
handlers.ask_new_subscription_pool_decision_message_handler,
NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
aiogram.F.text == constants.BACK_BUTTON,
)
router.message.register(
handlers.set_add_subscription_pool_description_message_handler,
AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
handlers.set_new_subscription_pool_description_message_handler,
NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
)
router.message.register(
handlers.set_add_subscription_pool_payment_data_from_profile_message_handler,
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
handlers.set_new_subscription_pool_payment_data_from_profile_message_handler,
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
aiogram.F.text == constants.USE_PROFILE_GIFT_PAYMENT_DATA,
)
router.message.register(
handlers.ask_add_subscription_pool_description_message_handler,
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
handlers.ask_new_subscription_pool_description_message_handler,
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
aiogram.F.text == constants.BACK_BUTTON,
)
router.message.register(
handlers.set_add_subscription_pool_payment_phone_message_handler,
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
handlers.set_new_subscription_pool_payment_phone_message_handler,
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
)
router.message.register(
handlers.set_add_subscription_pool_payment_phone_message_handler,
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
handlers.set_new_subscription_pool_payment_phone_message_handler,
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
aiogram.F.text == constants.BACK_BUTTON,
)
router.message.register(
handlers.set_add_subscription_pool_payment_bank_message_handler,
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
handlers.set_new_subscription_pool_payment_bank_message_handler,
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
)
#### Choose pool for subscription
router.callback_query.register(
handlers.show_new_subscription_choosing_pools_callback_handler,
NewSubscriptionState.WAITING_FOR_CHOOSE_POOL,
PoolsCallbackData.filter(),
)
router.callback_query.register(
handlers.ask_new_subscription_pool_decision_callback_handler,
NewSubscriptionState.WAITING_FOR_CHOOSE_POOL,
PoolsBackCallbackData.filter(),
)
router.callback_query.register(
handlers.show_new_subscription_choosing_pool_callback_handler,
NewSubscriptionState.WAITING_FOR_CHOOSE_POOL,
PoolCallbackData.filter(aiogram.F.action == PoolActionEnum.SHOW),
)
router.callback_query.register(
handlers.choose_new_subscription_pool_callback_handler,
NewSubscriptionState.WAITING_FOR_CHOOSE_POOL,
PoolCallbackData.filter(aiogram.F.action == PoolActionEnum.CHOOSE),
)
router.callback_query.register(
handlers.show_new_subscription_choosing_pools_callback_handler,
NewSubscriptionState.WAITING_FOR_CHOOSE_POOL,
PoolsCallbackData.filter(),
)
# Fallback
router.message.register(handlers.fallback_message_handler)

View File

@@ -1,21 +1,13 @@
import asyncio
import uuid
from aiogram import types, F, Router
from aiogram import types
from aiogram.enums import MessageOriginType, ParseMode
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
from pydantic_core import PydanticCustomError
from pydantic_filters import PagePagination
from pydantic_extra_types.phone_numbers import PhoneNumber
from birthday_pool_bot.dto import (
BankEnum,
PaymentData,
Pool,
Subscription,
SubscriptionFilter,
User,
)
from birthday_pool_bot.repositories.repositories import (
@@ -24,18 +16,11 @@ from birthday_pool_bot.repositories.repositories import (
UsersRepository,
)
from . import constants, logic
from .callback_data import (
AddSubscriptionCallbackData,
AddSubscriptionConfirmCallbackData,
ConfirmAnswerEnum,
MenuCallbackData,
SubscriptionCallbackData,
SubscriptionsCallbackData,
)
from .callback_data import PoolCallbackData, SubscriptionCallbackData
from .exceptions import FlowInternalError
from .states import (
AddSubscriptionPoolState,
AddSubscriptionState,
NewSubscriptionPoolState,
NewSubscriptionState,
MenuState,
SetProfileBirthdayState,
SetProfileGiftPaymentDataState,
@@ -322,31 +307,31 @@ async def delete_subscription_callback(
await state.set_state(MenuState.SUBSCRIPTIONS)
async def add_subscription_message_handler(
async def new_subscription_message_handler(
message: types.Message,
state: FSMContext,
):
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
async def add_subscription_callback_handler(
async def new_subscription_callback_handler(
callback_query: types.CallbackQuery,
state: FSMContext,
):
await logic.ask_add_subscription_user(callback_query=callback_query)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(callback_query=callback_query)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
async def ask_add_subscription_user_message_handler(
async def ask_new_subscription_user_message_handler(
message: types.Message,
state: FSMContext,
):
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
async def set_add_subscription_user_message_handler(
async def set_new_subscription_user_message_handler(
message: types.Message,
state: FSMContext,
user: User,
@@ -370,15 +355,15 @@ async def set_add_subscription_user_message_handler(
await message.reply(
text="Пользователь скрыл свои данные, попробуйте отправить номер телефона или его контакт",
)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
if message.forward_origin.type != MessageOriginType.USER:
await message.reply(
text="Это сообщение не от пользователя, попробуйте ещё раз",
)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
user_name = get_telegram_user_full_name(message.forward_origin.sender_user)
user_telegram_id = message.forward_origin.sender_user.id
@@ -390,8 +375,8 @@ async def set_add_subscription_user_message_handler(
try:
PhoneNumber._validate(user_phone, None)
except PydanticCustomError:
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
subscription_user = await users_repository.get_user_by_phone(phone=user_phone)
@@ -406,8 +391,8 @@ async def set_add_subscription_user_message_handler(
if subscription_user.id == user.id:
await message.reply("Нельзя подписаться на самого себя")
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
async with subscriptions_repository.transaction():
@@ -418,8 +403,8 @@ async def set_add_subscription_user_message_handler(
if subscription is not None:
await message.reply(text="У вас уже есть подписка на этого человека")
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.update_data(
@@ -427,65 +412,65 @@ async def set_add_subscription_user_message_handler(
)
if subscription_user.birthday is None:
await logic.ask_add_subscription_user_birthday(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_DATE)
await logic.ask_new_subscription_user_birthday(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_DATE)
return
await logic.ask_add_subscription_name(
await logic.ask_new_subscription_name(
message=message,
users_repository=users_repository,
subscription_user_id=subscription_user.id,
)
await state.set_state(AddSubscriptionState.WAITING_FOR_NAME)
await state.set_state(NewSubscriptionState.WAITING_FOR_NAME)
async def ask_add_subscription_user_birthday_message_handler(
async def ask_new_subscription_user_birthday_message_handler(
message: types.Message,
state: FSMContext,
):
await logic.ask_add_subscription_user_birthday(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_DATE)
await logic.ask_new_subscription_user_birthday(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_DATE)
async def set_add_subscription_user_birthday_message_handler(
async def set_new_subscription_user_birthday_message_handler(
message: types.Message,
state: FSMContext,
users_repository: UsersRepository,
):
birthday = parse_date(message=message)
if birthday is None:
await logic.ask_add_subscription_user_birthday(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_DATE)
await logic.ask_new_subscription_user_birthday(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_DATE)
return
state_data = await state.get_data()
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
async with users_repository.transaction():
subscription_user = await users_repository.get_user_by_id(user_id=subscription_user_id)
if subscription_user is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
subscription_user.birthday = birthday
await users_repository.update_user(user=subscription_user)
await logic.ask_add_subscription_name(
await logic.ask_new_subscription_name(
message=message,
users_repository=users_repository,
subscription_user_id=subscription_user.id,
)
await state.set_state(AddSubscriptionState.WAITING_FOR_NAME)
await state.set_state(NewSubscriptionState.WAITING_FOR_NAME)
async def ask_add_subscription_name_message_handler(
async def ask_new_subscription_name_message_handler(
message: types.Message,
state: FSMContext,
users_repository: UsersRepository,
@@ -494,26 +479,26 @@ async def ask_add_subscription_name_message_handler(
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
try:
await logic.ask_add_subscription_name(
await logic.ask_new_subscription_name(
message=message,
users_repository=users_repository,
subscription_user_id=subscription_user_id,
)
except FlowInternalError:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.set_state(AddSubscriptionState.WAITING_FOR_NAME)
await state.set_state(NewSubscriptionState.WAITING_FOR_NAME)
async def set_add_subscription_name_message_handler(
async def set_new_subscription_name_message_handler(
message: types.Message,
state: FSMContext,
user: User,
@@ -525,29 +510,29 @@ async def set_add_subscription_name_message_handler(
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
async with users_repository.transaction():
subscription_user = await users_repository.get_user_by_id(user_id=subscription_user_id)
if subscription_user is None or subscription_user.birthday is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.update_data(subscription_name=message.text)
await logic.ask_add_subscription_pool_decision(
await logic.ask_new_subscription_pool_decision(
message=message,
pools_repository=pools_repository,
users_repository=users_repository,
subscription_user_id=subscription_user_id,
)
await state.set_state(AddSubscriptionState.WAITING_FOR_POOL_DECISION)
await state.set_state(NewSubscriptionState.WAITING_FOR_POOL_DECISION)
async def ask_add_subscription_pool_decision_message_handler(
async def ask_new_subscription_pool_decision_message_handler(
message: types.Message,
state: FSMContext,
pools_repository: PoolsRepository,
@@ -557,12 +542,12 @@ async def ask_add_subscription_pool_decision_message_handler(
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
try:
await logic.ask_add_subscription_pool_decision(
await logic.ask_new_subscription_pool_decision(
message=message,
pools_repository=pools_repository,
users_repository=users_repository,
@@ -570,72 +555,235 @@ async def ask_add_subscription_pool_decision_message_handler(
)
except FlowInternalError:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.set_state(AddSubscriptionState.WAITING_FOR_POOL_DECISION)
await state.set_state(NewSubscriptionState.WAITING_FOR_POOL_DECISION)
async def show_add_subscription_pools_message_handler(
async def ask_new_subscription_pool_decision_callback_handler(
callback_query: types.Message,
state: FSMContext,
pools_repository: PoolsRepository,
users_repository: UsersRepository,
):
state_data = await state.get_data()
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
try:
await logic.ask_new_subscription_pool_decision(
message=callback_query.message,
pools_repository=pools_repository,
users_repository=users_repository,
subscription_user_id=subscription_user_id,
)
except FlowInternalError:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.set_state(NewSubscriptionState.WAITING_FOR_POOL_DECISION)
async def show_new_subscription_choosing_pools_message_handler(
message: types.Message,
state: FSMContext,
user: User,
users_repository: UsersRepository,
pools_repository: PoolsRepository,
):
state_data = await state.get_data()
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
try:
await logic.show_add_subscription_pools(
await logic.show_new_subscription_choosing_pools(
user=user,
users_repository=users_repository,
pools_repository=pools_repository,
subscription_user_id=subscription_user_id,
message=message,
)
except FlowInternalError:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await logic.ask_add_subscription_pool_description(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
async def ask_add_subscription_pool_description_message_handler(
async def show_new_subscription_choosing_pools_callback_handler(
callback_query: types.CallbackQuery,
state: FSMContext,
user: User,
users_repository: UsersRepository,
pools_repository: PoolsRepository,
):
state_data = await state.get_data()
subscription_user_id = state_data.get("subscription_user_id")
if subscription_user_id is None:
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
try:
await logic.show_new_subscription_choosing_pools(
user=user,
users_repository=users_repository,
pools_repository=pools_repository,
subscription_user_id=subscription_user_id,
message=callback_query.message,
)
except FlowInternalError:
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
async def show_new_subscription_choosing_pool_callback_handler(
callback_query: types.CallbackQuery,
state: FSMContext,
pools_repository: PoolsRepository,
):
callback_data = PoolCallbackData.unpack(callback_query.data)
try:
await logic.show_new_subscription_choosing_pool(
pools_repository=pools_repository,
pool_id=callback_data.id,
callback_query=callback_query,
)
except FlowInternalError:
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.show_new_subscription_choosing_pools(
user=user,
users_repository=users_repository,
pools_repository=pools_repository,
subscription_user_id=subscription_user_id,
)
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
return
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
async def choose_new_subscription_pool_callback_handler(
callback_query: types.CallbackQuery,
state: FSMContext,
users_repository: UsersRepository,
pools_repository: PoolsRepository,
):
state_data = await state.get_data()
subscription_user_id = state_data.get("subscription_user_id")
subscription_name = state_data.get("subscription_name")
if not all((subscription_user_id, subscription_name)):
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
async with users_repository.transaction():
subscription_user = await users_repository.get_user_by_id(
user_id=subscription_user_id,
)
if subscription_user is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
callback_data = PoolCallbackData.unpack(callback_query.data)
async with pools_repository.transaction():
subscription_pool = await pools_repository.get_pool_by_id(
pool_id=callback_data.id,
)
if subscription_pool is None:
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.show_new_subscription_choosing_pools(
user=user,
users_repository=users_repository,
pools_repository=pools_repository,
subscription_user_id=subscription_user_id,
callback_query=callback_query,
)
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
return
await state.update_data(
subscription_pool_id=callback_data.id,
)
try:
await logic.ask_new_subscription_confirmation(
message=callback_query.message,
users_repository=users_repository,
pools_repository=pools_repository,
subscription_name=subscription_name,
subscription_user_id=subscription_user_id,
subscription_pool_id=callback_data.id,
)
except FlowInternalError:
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.show_new_subscription_choosing_pools(
message=callback_query.message,
users_repository=users_repository,
pools_repository=pools_repository,
subscription_name=subscription_name,
subscription_user_id=subscription_user_id,
subscription_pool_id=callback_data.id,
)
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
return
await state.set_state(NewSubscriptionState.WAITING_FOR_CONFIRMATION)
async def ask_new_subscription_pool_description_message_handler(
message: types.Message,
state: FSMContext,
):
await logic.ask_add_subscription_pool_description(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
await logic.ask_new_subscription_pool_description(message=message)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
async def set_add_subscription_pool_description_message_handler(
async def set_new_subscription_pool_description_message_handler(
message: types.Message,
state: FSMContext,
):
description = message.text
await state.update_data(subscription_pool_description=description)
await logic.ask_add_subscription_pool_payment_phone(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
await logic.ask_new_subscription_pool_payment_phone(message=message)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
async def ask_add_subscription_pool_payment_phone_message_handler(
async def ask_new_subscription_pool_payment_phone_message_handler(
message: types.Message,
state: FSMContext,
user: User,
):
await logic.ask_add_subscription_pool_payment_phone(message=message, user=user)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
await logic.ask_new_subscription_pool_payment_phone(message=message, user=user)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
async def set_add_subscription_pool_payment_phone_message_handler(
async def set_new_subscription_pool_payment_phone_message_handler(
message: types.Message,
state: FSMContext,
):
@@ -646,8 +794,8 @@ async def set_add_subscription_pool_payment_phone_message_handler(
phone_number = message.text
else:
await message.reply(text="Некорректный номер телефона, попробуйте ещё раз")
await logic.ask_add_subscription_pool_payment_phone(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
await logic.ask_new_subscription_pool_payment_phone(message=message)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
return
try:
@@ -656,16 +804,16 @@ async def set_add_subscription_pool_payment_phone_message_handler(
await message.reply(
text="Некорректный номер телефона, попробуйте ещё раз",
)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
return
await state.update_data(subscription_pool_phone=phone_number)
await logic.ask_add_subscription_pool_payment_bank(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK)
await logic.ask_new_subscription_pool_payment_bank(message=message)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK)
async def set_add_subscription_pool_payment_data_from_profile_message_handler(
async def set_new_subscription_pool_payment_data_from_profile_message_handler(
message: types.Message,
state: FSMContext,
user: User,
@@ -674,8 +822,8 @@ async def set_add_subscription_pool_payment_data_from_profile_message_handler(
):
if user.gift_payment_data is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_pool_payment_phone(message=message, user=user)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
await logic.ask_new_subscription_pool_payment_phone(message=message, user=user)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
return
state_data = await state.get_data()
@@ -684,15 +832,15 @@ async def set_add_subscription_pool_payment_data_from_profile_message_handler(
subscription_pool_description = state_data.get("subscription_pool_description")
if not all((subscription_user_id, subscription_name)):
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.update_data(
subscription_pool_phone=user.gift_payment_data.phone,
subscription_pool_bank=user.gift_payment_data.bank,
)
await logic.ask_add_subscription_confirmation(
await logic.ask_new_subscription_confirmation(
message=message,
users_repository=users_repository,
pools_repository=pools_repository,
@@ -702,18 +850,18 @@ async def set_add_subscription_pool_payment_data_from_profile_message_handler(
subscription_pool_phone=user.gift_payment_data.phone,
subscription_pool_bank=user.gift_payment_data.bank,
)
await state.set_state(AddSubscriptionState.WAITING_FOR_CONFIRMATION)
await state.set_state(NewSubscriptionState.WAITING_FOR_CONFIRMATION)
async def ask_add_subscription_pool_payment_bank_message_handler(
async def ask_new_subscription_pool_payment_bank_message_handler(
message: types.Message,
state: FSMContext,
):
await logic.ask_add_subscription_pool_payment_bank(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK)
await logic.ask_new_subscription_pool_payment_bank(message=message)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK)
async def set_add_subscription_pool_payment_bank_message_handler(
async def set_new_subscription_pool_payment_bank_message_handler(
message: types.Message,
state: FSMContext,
users_repository: UsersRepository,
@@ -726,13 +874,13 @@ async def set_add_subscription_pool_payment_bank_message_handler(
subscription_pool_phone = state_data.get("subscription_pool_phone")
if not all((subscription_user_id, subscription_name)):
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
if subscription_pool_phone is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_pool_decision(message=message)
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
await logic.ask_new_subscription_pool_decision(message=message)
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
return
async with users_repository.transaction():
@@ -741,8 +889,8 @@ async def set_add_subscription_pool_payment_bank_message_handler(
)
if subscription_user is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
bank_name = message.text
@@ -754,7 +902,7 @@ async def set_add_subscription_pool_payment_bank_message_handler(
bank = constants.BANKS_MAP[bank_name]
await state.update_data(subscription_pool_bank=bank)
await logic.ask_add_subscription_confirmation(
await logic.ask_new_subscription_confirmation(
message=message,
users_repository=users_repository,
pools_repository=pools_repository,
@@ -764,10 +912,10 @@ async def set_add_subscription_pool_payment_bank_message_handler(
subscription_pool_phone=subscription_pool_phone,
subscription_pool_bank=bank,
)
await state.set_state(AddSubscriptionState.WAITING_FOR_CONFIRMATION)
await state.set_state(NewSubscriptionState.WAITING_FOR_CONFIRMATION)
async def ask_add_subscription_confirmation_message_handler(
async def ask_new_subscription_confirmation_message_handler(
message: types.Message,
state: FSMContext,
users_repository: UsersRepository,
@@ -782,8 +930,8 @@ async def ask_add_subscription_confirmation_message_handler(
subscription_pool_bank = state_data.get("subscription_pool_bank")
if not all((subscription_user_id, subscription_name)):
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
async with users_repository.transaction():
@@ -792,12 +940,12 @@ async def ask_add_subscription_confirmation_message_handler(
)
if subscription_user is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
try:
await logic.ask_add_subscription_confirmation(
await logic.ask_new_subscription_confirmation(
message=message,
users_repository=users_repository,
pools_repository=pools_repository,
@@ -810,14 +958,14 @@ async def ask_add_subscription_confirmation_message_handler(
)
except FlowInternalError:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await logic.ask_new_subscription_user(message=message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
await state.set_state(AddSubscriptionState.WAITING_FOR_CONFIRMATION)
await state.set_state(NewSubscriptionState.WAITING_FOR_CONFIRMATION)
async def confirm_add_subscription_callback_handler(
async def confirm_new_subscription_callback_handler(
callback_query: types.CallbackQuery,
state: FSMContext,
user: User,
@@ -833,9 +981,9 @@ async def confirm_add_subscription_callback_handler(
subscription_pool_phone = state_data.get("subscription_pool_phone")
subscription_pool_bank = state_data.get("subscription_pool_bank")
if not all((subscription_user_id, subscription_name)):
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
async with users_repository.transaction():
@@ -843,9 +991,9 @@ async def confirm_add_subscription_callback_handler(
user_id=subscription_user_id,
)
if subscription_user is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
subscription_pool = None
@@ -855,9 +1003,9 @@ async def confirm_add_subscription_callback_handler(
pool_id=subscription_pool_id,
)
if subscription_pool is None:
await message.reply(text=constants.ERROR_MESSAGE)
await logic.ask_add_subscription_user(message=message)
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
await callback_query.answer(text=constants.ERROR_MESSAGE)
await logic.ask_new_subscription_user(message=callback_query.message)
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
return
if subscription_pool is None and all((subscription_pool_phone, subscription_pool_bank)):

View File

@@ -1,17 +1,26 @@
import uuid
from aiogram import types
from aiogram.enums import ParseMode
from aiogram.fsm.context import FSMContext
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
from pydantic_filters import PagePagination
from birthday_pool_bot.dto import User
from birthday_pool_bot.repositories.repositories import UsersRepository
from birthday_pool_bot.dto import BankEnum, User
from birthday_pool_bot.repositories.repositories import (
PoolsRepository,
SubscriptionsRepository,
UsersRepository,
)
from . import constants
from .callback_data import (
AddSubscriptionCallbackData,
AddSubscriptionConfirmCallbackData,
ConfirmAnswerEnum,
MenuCallbackData,
NewSubscriptionCallbackData,
NewSubscriptionConfirmCallbackData,
PoolActionEnum,
PoolCallbackData,
PoolsCallbackData,
PoolsBackCallbackData,
SubscriptionActionEnum,
SubscriptionCallbackData,
SubscriptionsCallbackData,
@@ -200,12 +209,12 @@ async def show_subscriptions(
text = "Мои подписки:" if subscriptions else "Нет подписок"
keyboard = InlineKeyboardBuilder()
for subscription in subscriptions:
keyboard.button(
keyboard.row(types.InlineKeyboardButton(
text=subscription.name,
callback_data=SubscriptionCallbackData(
to_user_id=subscription.to_user_id,
).pack(),
)
))
navigation_row = []
if page > 1:
navigation_row.append(types.InlineKeyboardButton(
@@ -226,7 +235,7 @@ async def show_subscriptions(
keyboard.row(
types.InlineKeyboardButton(
text="Добавить",
callback_data=AddSubscriptionCallbackData().pack(),
callback_data=NewSubscriptionCallbackData().pack(),
),
types.InlineKeyboardButton(
text="Назад",
@@ -273,7 +282,12 @@ async def show_subscription(
)
if subscription.pool is not None:
if subscription.pool.owner_id == from_user_id:
text += "Вы собираете деньги\n\n"
bank_title = constants.BANKS_TITLE_MAP[subscription.pool.payment_data.bank]
text += (
"Вы собираете деньги на:\n"
f"_Телефон_: {subscription.pool.payment_data.phone}\n"
f"_Банк_: {bank_title}\n\n"
)
else:
text += "Вы участвуете в сборе денег\n\n"
keyboard = InlineKeyboardBuilder()
@@ -333,7 +347,7 @@ async def delete_subscription(
await callback_query.answer(text="Подписка успешно удалена")
async def ask_add_subscription_user(
async def ask_new_subscription_user(
callback_query: types.CallbackQuery | None = None,
message: types.Message | None = None,
):
@@ -367,7 +381,7 @@ async def ask_add_subscription_user(
)
async def ask_add_subscription_user_birthday(
async def ask_new_subscription_user_birthday(
message: types.Message,
):
text = (
@@ -388,7 +402,7 @@ async def ask_add_subscription_user_birthday(
)
async def ask_add_subscription_name(
async def ask_new_subscription_name(
message: types.Message,
users_repository: UsersRepository,
subscription_user_id: uuid.UUID,
@@ -422,7 +436,7 @@ async def ask_add_subscription_name(
)
async def ask_add_subscription_pool_decision(
async def ask_new_subscription_pool_decision(
message: types.Message,
pools_repository: PoolsRepository,
users_repository: UsersRepository,
@@ -458,9 +472,11 @@ async def ask_add_subscription_pool_decision(
)
async def show_add_subscription_pools(
async def show_new_subscription_choosing_pools(
user: User,
users_repository: UsersRepository,
pools_repository: PoolsRepository,
subscription_user_id: uuid.UUID,
message: types.Message | None = None,
callback_query: types.CallbackQuery | None = None,
):
@@ -470,31 +486,34 @@ async def show_add_subscription_pools(
callback_data = SubscriptionsCallbackData.unpack(callback_query.data)
page = callback_data.page
async with subscriptions_repository.transaction():
total = await subscriptions_repository.get_user_subscriptions_count(user_id=user.id)
async with pools_repository.transaction():
total = await pools_repository.get_pools_by_birthday_user_id_count(
birthday_user_id=subscription_user_id,
)
pages_count = total // per_page + int(bool(total % per_page))
subscriptions = [
subscription
async for subscription in subscriptions_repository.get_user_subscriptions(
user_id=user.id,
pools = [
pool
async for pool in pools_repository.get_pools_by_birthday_user_id(
birthday_user_id=subscription_user_id,
pagination=PagePagination(page=page, per_page=per_page),
with_owner=True,
)
]
text = "Сборы:" if subscriptions else "Нет сборов"
text = "Сборы:" if pools else "Нет сборов"
keyboard = InlineKeyboardBuilder()
for subscription in subscriptions:
keyboard.button(
text=subscription.name,
callback_data=SubscriptionCallbackData(
to_user_id=subscription.to_user_id,
for pool in pools:
keyboard.row(types.InlineKeyboardButton(
text=pool.owner.name or "Аноним",
callback_data=PoolCallbackData(
id=pool.id,
).pack(),
)
))
navigation_row = []
if page > 1:
navigation_row.append(types.InlineKeyboardButton(
text="<",
callback_data=SubscriptionsCallbackData(page=page - 1).pack(),
callback_data=PoolsCallbackData(page=page - 1).pack(),
))
if pages_count > 1:
navigation_row.append(types.InlineKeyboardButton(
@@ -504,17 +523,13 @@ async def show_add_subscription_pools(
if page < pages_count:
navigation_row.append(types.InlineKeyboardButton(
text=">",
callback_data=SubscriptionsCallbackData(page=page + 1).pack(),
callback_data=PoolsCallbackData(page=page + 1).pack(),
))
keyboard.row(*navigation_row)
keyboard.row(
types.InlineKeyboardButton(
text="Добавить",
callback_data=AddSubscriptionCallbackData().pack(),
),
types.InlineKeyboardButton(
text="Назад",
callback_data=MenuCallbackData().pack(),
callback_data=PoolsBackCallbackData().pack(),
),
)
reply_markup = keyboard.as_markup()
@@ -535,7 +550,70 @@ async def show_add_subscription_pools(
)
async def ask_add_subscription_pool_description(
async def show_new_subscription_choosing_pool(
pools_repository: PoolsRepository,
pool_id: uuid.UUID,
message: types.Message | None = None,
callback_query: types.CallbackQuery | None = None,
):
async with pools_repository.transaction():
pool = await pools_repository.get_pool_by_id(
pool_id=pool_id,
with_owner=True,
with_birthday_user=True,
)
if pool is None:
raise FlowInternalError()
owner_name = (
pool.owner.name
or pool.owner.phone
or pool.owner.telegram_id
)
birthday_user_name = (
pool.birthday_user.name
or pool.birthday_user.phone
or pool.birthday_user.telegram_id
)
bank_name = constants.BANKS_TITLE_MAP[pool.payment_data.bank]
text = (
f"*{owner_name}* собирает деньги для {birthday_user_name}\n\n"
"Данные для отправки подарка:\n"
f"_Телефон_: {pool.payment_data.phone}\n"
f"_Банк_: {bank_name}\n"
)
keyboard = InlineKeyboardBuilder()
keyboard.button(
text="Выбрать",
callback_data=PoolCallbackData(
id=pool_id,
action=PoolActionEnum.CHOOSE,
).pack(),
)
keyboard.button(
text="Назад",
callback_data=PoolsCallbackData().pack()
)
keyboard.adjust(2)
reply_markup = keyboard.as_markup()
if message is not None:
await message.reply(
text=text,
parse_mode=ParseMode.MARKDOWN,
reply_markup=reply_markup,
)
elif callback_query is not None:
await callback_query.message.edit_text(
text=text,
parse_mode=ParseMode.MARKDOWN,
)
await callback_query.message.edit_reply_markup(
reply_markup=reply_markup,
)
async def ask_new_subscription_pool_description(
message: types.Message,
):
keyboard = ReplyKeyboardBuilder()
@@ -554,7 +632,7 @@ async def ask_add_subscription_pool_description(
)
async def ask_add_subscription_pool_payment_phone(
async def ask_new_subscription_pool_payment_phone(
message: types.Message,
user: User,
):
@@ -589,7 +667,7 @@ async def ask_add_subscription_pool_payment_phone(
)
async def ask_add_subscription_pool_payment_bank(
async def ask_new_subscription_pool_payment_bank(
message: types.Message,
):
text = "Выберите банк для приёма платежей"
@@ -611,7 +689,7 @@ async def ask_add_subscription_pool_payment_bank(
)
async def ask_add_subscription_confirmation(
async def ask_new_subscription_confirmation(
message: types.Message,
users_repository: UsersRepository,
pools_repository: PoolsRepository,
@@ -663,13 +741,13 @@ async def ask_add_subscription_confirmation(
keyboard = InlineKeyboardBuilder()
keyboard.button(
text="Да",
callback_data=AddSubscriptionConfirmCallbackData(
callback_data=NewSubscriptionConfirmCallbackData(
answer=ConfirmAnswerEnum.YES,
).pack(),
)
keyboard.button(
text="Нет",
callback_data=AddSubscriptionConfirmCallbackData(
callback_data=NewSubscriptionConfirmCallbackData(
answer=ConfirmAnswerEnum.NO,
).pack(),
)

View File

@@ -24,15 +24,16 @@ class SetProfileGiftPaymentDataState(StatesGroup):
WAITING_FOR_BANK = State()
class AddSubscriptionState(StatesGroup):
class NewSubscriptionState(StatesGroup):
WAITING_FOR_PHONE = State()
WAITING_FOR_DATE = State()
WAITING_FOR_NAME = State()
WAITING_FOR_POOL_DECISION = State()
WAITING_FOR_CHOOSE_POOL = State()
WAITING_FOR_CONFIRMATION = State()
class AddSubscriptionPoolState(StatesGroup):
class NewSubscriptionPoolState(StatesGroup):
WAITING_FOR_DESCRIPTION = State()
WAITING_FOR_PAYMENT_PHONE = State()
WAITING_FOR_PAYMENT_BANK = State()

View File

@@ -5,7 +5,7 @@ from aiogram import types
from aiogram.types import User as TelegramUser
BIRTHDATE_REGEXP = re.compile("^(?P<day>\d{2})\.(?P<month>\d{2})\.(?P<year>\d{4})$")
BIRTHDATE_REGEXP = re.compile(r"^(?P<day>\d{2}).(?P<month>\d{2}).(?P<year>\d{4})$")
def parse_date(message: types.Message) -> datetime.date:

View File

@@ -3,6 +3,7 @@ from typing import Any
import aiogram
import fastapi
import uvicorn
import yarl
from birthday_pool_bot.telegram_bot.base import BaseTelegramBotService
@@ -14,9 +15,10 @@ class UvicornServer(uvicorn.Server):
class TelegramBotWebhookService(BaseTelegramBotService):
async def listen_events(self):
webhook_url = yarl.URL(str(self._settings.root_url)) / self._settings.root_path.lstrip("/")
await self._bot.set_webhook(
url=self._settings.url,
secret_token=self._settings.secret_token,
url=str(webhook_url),
secret_token=self._settings.secret_access_key,
)
await self.get_server().serve()
@@ -26,10 +28,9 @@ class TelegramBotWebhookService(BaseTelegramBotService):
root_url=self._settings.root_url,
root_path=self._settings.root_path,
)
app.post("")(self.handler)
app.post(self._webhook_path)(self.handler)
config = uvicorn.Config(app=app, host="0.0.0.0", port=self._port)
config = uvicorn.Config(app=app, host="0.0.0.0", port=self._settings.port)
return UvicornServer(config)
async def handler(
@@ -37,7 +38,7 @@ class TelegramBotWebhookService(BaseTelegramBotService):
update: dict[str, Any],
x_telegram_bot_api_secret_token: str | None = fastapi.Header(None),
):
if x_telegram_bot_api_secret_token != self._secret_token:
if x_telegram_bot_api_secret_token != self._settings.secret_access_key:
raise fastapi.HTTPException(
status_code=fastapi.status.HTTP_403_FORBIDDEN,
detail="Forbidden.",

View File

@@ -7,7 +7,7 @@ from birthday_pool_bot.telegram_bot.settings import TelegramBotSettings
class TelegramBotWebhookSettings(TelegramBotSettings):
method: Literal[TelegramBotMethodEnum.WEBHOOK.value] = TelegramBotMethodEnum.WEBHOOK
method: Literal[TelegramBotMethodEnum.WEBHOOK.value] = TelegramBotMethodEnum.WEBHOOK.value
root_url: AnyHttpUrl
root_path: str = "/"