Fix parsing phone and add redis storage for FSM in telegram bot
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import aiogram
|
||||
import facet
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
|
||||
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||
from .settings import TelegramBotSettings
|
||||
from .storage import get_telegram_bot_fsm_storage
|
||||
from .ui import setup_dispatcher
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ class BaseTelegramBotService(facet.AsyncioServiceMixin):
|
||||
):
|
||||
self._settings = settings
|
||||
self._repositories_container = repositories_container
|
||||
self._dispatcher = aiogram.Dispatcher(storage=MemoryStorage())
|
||||
self._dispatcher = aiogram.Dispatcher(
|
||||
storage=get_telegram_bot_fsm_storage(settings=settings.storage),
|
||||
)
|
||||
self._bot = aiogram.Bot(token=settings.token)
|
||||
|
||||
setup_dispatcher(
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .enums import TelegramBotMethodEnum
|
||||
from .storage import MemoryStorageSettings, RedisStorageSettings
|
||||
|
||||
|
||||
class TelegramBotSettings(BaseModel):
|
||||
method: TelegramBotMethodEnum = TelegramBotMethodEnum.POLLING
|
||||
token: str = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
token: str = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
storage: (
|
||||
MemoryStorageSettings |
|
||||
RedisStorageSettings
|
||||
) = MemoryStorageSettings()
|
||||
|
||||
16
birthday_pool_bot/telegram_bot/storage/__init__.py
Normal file
16
birthday_pool_bot/telegram_bot/storage/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from .fabric import get_telegram_bot_fsm_storage
|
||||
from .settings import (
|
||||
MemoryStorageSettings,
|
||||
RedisStorageSettings,
|
||||
StorageSettings,
|
||||
)
|
||||
|
||||
|
||||
__all__ = (
|
||||
# fabric
|
||||
"get_telegram_bot_fsm_storage",
|
||||
# settings
|
||||
"MemoryStorageSettings",
|
||||
"RedisStorageSettings",
|
||||
"StorageSettings",
|
||||
)
|
||||
6
birthday_pool_bot/telegram_bot/storage/enums.py
Normal file
6
birthday_pool_bot/telegram_bot/storage/enums.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import enum
|
||||
|
||||
|
||||
class StorageTypeEnum(str, enum.Enum):
|
||||
MEMORY = "memory"
|
||||
REDIS = "redis"
|
||||
20
birthday_pool_bot/telegram_bot/storage/fabric.py
Normal file
20
birthday_pool_bot/telegram_bot/storage/fabric.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import redis
|
||||
from aiogram.fsm.storage.base import BaseStorage
|
||||
|
||||
from .enums import StorageTypeEnum
|
||||
from .settings import StorageSettings
|
||||
|
||||
|
||||
def get_telegram_bot_fsm_storage(settings: StorageSettings) -> BaseStorage:
|
||||
match settings.type:
|
||||
case StorageTypeEnum.MEMORY.value:
|
||||
return MemoryStorage()
|
||||
case StorageTypeEnum.REDIS.value:
|
||||
redis_client = redis.Redis(
|
||||
host=settings.host,
|
||||
port=settings.port,
|
||||
db=settings.database,
|
||||
)
|
||||
return RedisStorage(redis=redis_client)
|
||||
case _:
|
||||
raise ValueError(f"Unsupported telegram bot storage type: {settings.type}")
|
||||
20
birthday_pool_bot/telegram_bot/storage/settings.py
Normal file
20
birthday_pool_bot/telegram_bot/storage/settings.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .enums import StorageTypeEnum
|
||||
|
||||
|
||||
class StorageSettings(BaseModel):
|
||||
type: StorageTypeEnum
|
||||
|
||||
|
||||
class MemoryStorageSettings(StorageSettings):
|
||||
type: Literal[StorageTypeEnum.MEMORY.value] = StorageTypeEnum.MEMORY.value
|
||||
|
||||
|
||||
class RedisStorageSettings(StorageSettings):
|
||||
type: Literal[StorageTypeEnum.REDIS.value] = StorageTypeEnum.REDIS.value
|
||||
host: str = "localhost"
|
||||
port: int = 6379
|
||||
database: int = 0
|
||||
@@ -1,8 +1,6 @@
|
||||
from aiogram import types
|
||||
from aiogram.enums import MessageOriginType, ParseMode
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from pydantic_core import PydanticCustomError
|
||||
from pydantic_extra_types.phone_numbers import PhoneNumber
|
||||
|
||||
from birthday_pool_bot.dto import (
|
||||
PaymentData,
|
||||
@@ -27,7 +25,7 @@ from .states import (
|
||||
SetProfileNameState,
|
||||
SetProfilePhoneState,
|
||||
)
|
||||
from .utils import get_telegram_user_full_name, parse_date
|
||||
from .utils import get_telegram_user_full_name, parse_date, parse_phone
|
||||
|
||||
|
||||
async def fallback_message_handler(
|
||||
@@ -114,12 +112,10 @@ async def set_profile_phone_message_handler(
|
||||
await state.set_state(SetProfilePhoneState.WAITING_FOR_PHONE)
|
||||
return
|
||||
|
||||
phone_number = message.contact.phone_number
|
||||
try:
|
||||
PhoneNumber._validate(phone_number, None)
|
||||
except PydanticCustomError:
|
||||
phone_number = parse_phone(text=message.contact.phone_number)
|
||||
if phone_number is None:
|
||||
await message.reply(
|
||||
text="Некорректный номер телефон, попробуйте ещё раз",
|
||||
text="Некорректный номер телефона, попробуйте ещё раз",
|
||||
)
|
||||
await state.set_state(SetProfilePhoneState.WAITING_FOR_PHONE)
|
||||
return
|
||||
@@ -146,7 +142,7 @@ async def set_profile_birthdate_message_handler(
|
||||
user: User,
|
||||
users_repository: UsersRepository,
|
||||
):
|
||||
birthday = parse_date(message=message)
|
||||
birthday = parse_date(text=message.text)
|
||||
if birthday is None:
|
||||
await logic.ask_profile_birthdate(message=message)
|
||||
await state.set_state(SetProfileBirthdayState.WAITING_FOR_DATE)
|
||||
@@ -182,9 +178,8 @@ async def set_profile_gift_payment_phone_message_handler(
|
||||
await state.set_state(SetProfileGiftPaymentDataState.WAITING_FOR_PHONE)
|
||||
return
|
||||
|
||||
try:
|
||||
PhoneNumber._validate(phone_number, None)
|
||||
except PydanticCustomError:
|
||||
phone_number = parse_phone(text=phone_number)
|
||||
if phone_number is None:
|
||||
await message.reply(
|
||||
text="Некорректный номер телефон, попробуйте ещё раз",
|
||||
)
|
||||
@@ -371,10 +366,8 @@ async def set_new_subscription_user_message_handler(
|
||||
telegram_id=user_telegram_id,
|
||||
)
|
||||
elif message.text:
|
||||
user_phone = message.text
|
||||
try:
|
||||
PhoneNumber._validate(user_phone, None)
|
||||
except PydanticCustomError:
|
||||
user_phone = parse_phone(text=message.text)
|
||||
if user_phone is None:
|
||||
await logic.ask_new_subscription_user(message=message)
|
||||
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||
return
|
||||
@@ -437,7 +430,7 @@ async def set_new_subscription_user_birthday_message_handler(
|
||||
state: FSMContext,
|
||||
users_repository: UsersRepository,
|
||||
):
|
||||
birthday = parse_date(message=message)
|
||||
birthday = parse_date(text=message.text)
|
||||
if birthday is None:
|
||||
await logic.ask_new_subscription_user_birthday(message=message)
|
||||
await state.set_state(NewSubscriptionState.WAITING_FOR_DATE)
|
||||
@@ -798,9 +791,8 @@ async def set_new_subscription_pool_payment_phone_message_handler(
|
||||
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
||||
return
|
||||
|
||||
try:
|
||||
PhoneNumber._validate(phone_number, None)
|
||||
except PydanticCustomError:
|
||||
phone_number = parse_phone(text=phone_number)
|
||||
if phone_number is None:
|
||||
await message.reply(
|
||||
text="Некорректный номер телефона, попробуйте ещё раз",
|
||||
)
|
||||
|
||||
@@ -3,13 +3,15 @@ import re
|
||||
|
||||
from aiogram import types
|
||||
from aiogram.types import User as TelegramUser
|
||||
from pydantic_core import PydanticCustomError
|
||||
from pydantic_extra_types.phone_numbers import PhoneNumber
|
||||
|
||||
|
||||
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:
|
||||
if (re_match := BIRTHDATE_REGEXP.match(message.text)) is None:
|
||||
def parse_date(text: str) -> datetime.date | None:
|
||||
if (re_match := BIRTHDATE_REGEXP.match(text)) is None:
|
||||
return
|
||||
|
||||
return datetime.date(
|
||||
@@ -19,7 +21,18 @@ def parse_date(message: types.Message) -> datetime.date:
|
||||
)
|
||||
|
||||
|
||||
def parse_phone(text: str) -> str | None:
|
||||
phone = text
|
||||
if not phone.startswith("+"):
|
||||
phone = f"+{phone}"
|
||||
try:
|
||||
PhoneNumber._validate(phone, None)
|
||||
except PydanticCustomError:
|
||||
return
|
||||
|
||||
return phone
|
||||
|
||||
|
||||
def get_telegram_user_full_name(user: TelegramUser) -> str:
|
||||
name_parts = (user.first_name, user.last_name)
|
||||
return " ".join(filter(None, name_parts))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user