Fix bugs, add README and Makefile
This commit is contained in:
@@ -4,13 +4,14 @@ WORKDIR /app
|
||||
|
||||
RUN pip install uv && apt update && apt install -y git
|
||||
COPY pyproject.toml uv.lock README.md /app
|
||||
COPY birthday_pool_bot /app
|
||||
RUN uv sync
|
||||
COPY birthday_pool_bot /app/birthday_pool_bot
|
||||
ENTRYPOINT ["uv", "run"]
|
||||
|
||||
|
||||
FROM core AS app
|
||||
|
||||
RUN uv sync --group sqlite
|
||||
RUN uv sync --group sqlite --group postgresql
|
||||
ENTRYPOINT ["uv", "run", "python", "-m", "birthday_pool_bot"]
|
||||
|
||||
|
||||
|
||||
5
Makefile
Normal file
5
Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
lint:
|
||||
uv run ruff check
|
||||
|
||||
test:
|
||||
echo "Not implemented"
|
||||
27
README.md
27
README.md
@@ -1,4 +1,29 @@
|
||||
# Birthday Pool Bot
|
||||
|
||||
## Configuration
|
||||
## Run
|
||||
|
||||
Copy environment template file
|
||||
```shell
|
||||
cp .env.example .env
|
||||
```
|
||||
And edit `.env`
|
||||
|
||||
Install requirements
|
||||
```shell
|
||||
uv sync --all-groups
|
||||
```
|
||||
|
||||
Run
|
||||
```shell
|
||||
uv run python -m birthday_pool_bot -e .env run
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
* Поддержать рассылку пользователям о том, что появились новые сборы для их подписки (если они ещё
|
||||
не участвуют в сборе)
|
||||
* Добавить возможность добавлять ссылку на сбор денег Сбера, когда происходит оповещение о
|
||||
наступающем дне рождения
|
||||
* Добавить раздел с настройками времени оповещения о предстоящих событиях
|
||||
* Добавить возможность инициировать сбор денег по другому поводу (кроме ДР)
|
||||
* Добавить возможность отписаться во время нотификации о предстоящем ДР
|
||||
|
||||
@@ -46,6 +46,7 @@ class Pool(BaseModel):
|
||||
payment_data: PaymentData
|
||||
|
||||
owner: User | None = None
|
||||
birthday_user: User | None = None
|
||||
|
||||
|
||||
class PoolFilter(BaseFilter):
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import uuid
|
||||
from datetime import timedelta
|
||||
from typing import AsyncContextManager, AsyncGenerator, Protocol
|
||||
from typing import Any
|
||||
|
||||
from birthday_pool_bot.dto import Pool, User
|
||||
import pathlib
|
||||
from datetime import timedelta
|
||||
from typing import AsyncContextManager, Generator, Protocol
|
||||
|
||||
|
||||
class MessengerInterface(Protocol):
|
||||
|
||||
@@ -2,6 +2,7 @@ import asyncio
|
||||
|
||||
import typer
|
||||
|
||||
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||
from .service import NotificationsService
|
||||
from .settings import NotificationsSettings
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from aiogram.enums import ParseMode
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||
from .settings import NotificationsSettings
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import contextvars
|
||||
from contextlib import asynccontextmanager, contextmanager
|
||||
from typing import Generic, TypeVar
|
||||
from typing import AsyncGenerator, Generator, Generic, TypeVar
|
||||
|
||||
from pydantic_filters import BasePagination, BaseSort
|
||||
from pydantic_filters.drivers.sqlalchemy import append_to_statement
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
@@ -9,7 +10,9 @@ from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from sqlmodel import delete, insert, select, update
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from birthday_pool_bot.interfaces import RepositoryInterface
|
||||
from .exceptions import AlreadyExistsError, HaveNoSessionError
|
||||
from .settings import RepositorySettings
|
||||
from .tables import BaseSQLModel
|
||||
|
||||
|
||||
DTOType = TypeVar("DTOType")
|
||||
|
||||
@@ -12,7 +12,7 @@ from .migrator import Migrator
|
||||
def callback(ctx: typer.Context):
|
||||
ctx.obj = ctx.obj or {}
|
||||
|
||||
settings = ctx.obj["settings"]
|
||||
settings: Settings = ctx.obj["settings"]
|
||||
ctx.obj["migrator"] = Migrator(settings=settings.repository)
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def upgrade() -> None:
|
||||
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
|
||||
sa.Column("birthday", sa.Date(), nullable=True),
|
||||
sa.Column("phone", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
|
||||
sa.Column("telegram_id", sa.Integer(), nullable=True),
|
||||
sa.Column("telegram_id", sa.BigInteger(), nullable=True),
|
||||
sa.Column("gift_payment_data", sa.JSON(), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("id"),
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from pydantic_filters import OffsetPagination
|
||||
import uuid
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from pydantic_filters import BasePagination, OffsetPagination
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from birthday_pool_bot.dto import Pool, PoolFilter
|
||||
@@ -14,20 +17,38 @@ class PoolsRepository(BaseRepository[Pool, PoolFilter]):
|
||||
filter_ = PoolFilter(birthday_user_id={birthday_user_id})
|
||||
return await self.get_items_count(filter_=filter_)
|
||||
|
||||
async def get_pools_by_birthday_user_id(self, birthday_user_id: uuid.UUID) -> list[Pool]:
|
||||
async def get_pools_by_birthday_user_id(
|
||||
self,
|
||||
birthday_user_id: uuid.UUID,
|
||||
pagination: BasePagination | None = None,
|
||||
with_owner: bool = False,
|
||||
) -> AsyncGenerator[Pool]:
|
||||
filter_ = PoolFilter(birthday_user_id={birthday_user_id})
|
||||
return [pool async for pool in self.get_items(filter_=filter_)]
|
||||
options = []
|
||||
if with_owner:
|
||||
options.append(joinedload(DBPool.owner))
|
||||
|
||||
pools_generator = self.get_items(
|
||||
filter_=filter_,
|
||||
pagination=pagination,
|
||||
options=options,
|
||||
)
|
||||
async for pool in pools_generator:
|
||||
yield pool
|
||||
|
||||
async def get_pool_by_id(
|
||||
self,
|
||||
pool_id: uuid.UUID,
|
||||
with_owner: bool = False,
|
||||
with_birthday_user: bool = False,
|
||||
) -> Pool | None:
|
||||
filter_ = PoolFilter(id={pool_id})
|
||||
pagination = OffsetPagination(limit=1)
|
||||
options = []
|
||||
if with_owner:
|
||||
options.append(joinedload(DBPool.owner))
|
||||
if with_birthday_user:
|
||||
options.append(joinedload(DBPool.birthday_user))
|
||||
|
||||
pools_generator = self.get_items(
|
||||
filter_=filter_,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import uuid
|
||||
from typing import AsyncGenerator, Iterable
|
||||
|
||||
from pydantic_filters import BasePagination, OffsetPagination
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import uuid
|
||||
from datetime import date
|
||||
from typing import Container, Sequence, TypeVar
|
||||
|
||||
from pydantic_filters import OffsetPagination
|
||||
from sqlalchemy import Column, func, inspect, select
|
||||
from pydantic_filters import BasePagination, OffsetPagination
|
||||
from sqlalchemy import Column, func, inspect, or_, select, update
|
||||
from sqlmodel import SQLModel
|
||||
|
||||
from birthday_pool_bot.dto import User, UserFilter
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import uuid
|
||||
import enum
|
||||
from datetime import date
|
||||
from typing import Self, List
|
||||
from typing import Any, Self
|
||||
|
||||
import sqlalchemy as sa
|
||||
from pydantic import BaseModel
|
||||
from sqlmodel import SQLModel, Field, Relationship
|
||||
|
||||
from birthday_pool_bot.dto import (
|
||||
BankEnum,
|
||||
PaymentData as DTOPaymentData,
|
||||
Pool as DTOPool,
|
||||
Subscription as DTOSubscription,
|
||||
@@ -46,7 +45,10 @@ class User(BaseSQLModel, table=True):
|
||||
name: str | None = Field(nullable=True)
|
||||
birthday: date | None = Field(nullable=True)
|
||||
phone: str | None = Field(default=None, nullable=True)
|
||||
telegram_id: int | None = Field(default=None, nullable=True)
|
||||
telegram_id: int | None = Field(
|
||||
default=None,
|
||||
sa_column=sa.Column(sa.BigInteger(), nullable=True),
|
||||
)
|
||||
gift_payment_data: dict | None = Field(
|
||||
sa_column=sa.Column(sa.JSON, nullable=True),
|
||||
default_factory=dict,
|
||||
@@ -118,6 +120,12 @@ class Pool(BaseSQLModel, table=True):
|
||||
"lazy": None,
|
||||
},
|
||||
)
|
||||
birthday_user: User = Relationship(
|
||||
sa_relationship_kwargs={
|
||||
"primaryjoin": "User.id == Pool.birthday_user_id",
|
||||
"lazy": None,
|
||||
},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_item(cls, item: DTOPool) -> Self:
|
||||
@@ -128,6 +136,11 @@ class Pool(BaseSQLModel, table=True):
|
||||
description=item.description,
|
||||
payment_data=item.payment_data.model_dump_json(),
|
||||
owner=None if item.owner is None else DTOUser.from_item(item.owner),
|
||||
birthday_user=(
|
||||
None
|
||||
if item.birthday_user is None else
|
||||
DTOUser.from_item(item.birthday_user)
|
||||
),
|
||||
)
|
||||
|
||||
def to_item(self) -> DTOPool:
|
||||
@@ -137,7 +150,8 @@ class Pool(BaseSQLModel, table=True):
|
||||
birthday_user_id=self.birthday_user_id,
|
||||
description=self.description,
|
||||
payment_data=DTOPaymentData.model_validate_json(self.payment_data),
|
||||
owner=None if self.owner is None else self.owner.to_item()
|
||||
owner=None if self.owner is None else self.owner.to_item(),
|
||||
birthday_user=None if self.birthday_user is None else self.birthday_user.to_item(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ from .settings import TelegramBotSettings
|
||||
__all__ = (
|
||||
# cli
|
||||
"get_cli",
|
||||
# fabric
|
||||
"get_telegram_bot_service",
|
||||
# settings
|
||||
"TelegramBotSettings",
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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}'")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)):
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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 = "/"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
telegram-bot:
|
||||
notifications:
|
||||
database:
|
||||
|
||||
volumes:
|
||||
@@ -19,12 +19,19 @@ dependencies = [
|
||||
"aiogram>=3.23.0",
|
||||
"uvicorn>=0.38.0",
|
||||
"fastapi>=0.124.4",
|
||||
"yarl>=1.22.0",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
sqlite = [
|
||||
"aiosqlite>=0.21.0",
|
||||
]
|
||||
postgresql = [
|
||||
"asyncpg>=0.31.0",
|
||||
]
|
||||
dev = [
|
||||
"ruff>=0.14.11",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
package = false
|
||||
|
||||
84
uv.lock
generated
84
uv.lock
generated
@@ -182,6 +182,38 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/64/2e54428beba8d9992aa478bb8f6de9e4ecaa5f8f513bcfd567ed7fb0262d/apscheduler-3.11.2-py3-none-any.whl", hash = "sha256:ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d", size = 64439, upload-time = "2025-12-22T00:39:33.303Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asyncpg"
|
||||
version = "0.31.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fe/cc/d18065ce2380d80b1bcce927c24a2642efd38918e33fd724bc4bca904877/asyncpg-0.31.0.tar.gz", hash = "sha256:c989386c83940bfbd787180f2b1519415e2d3d6277a70d9d0f0145ac73500735", size = 993667, upload-time = "2025-11-24T23:27:00.812Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/11/97b5c2af72a5d0b9bc3fa30cd4b9ce22284a9a943a150fdc768763caf035/asyncpg-0.31.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c204fab1b91e08b0f47e90a75d1b3c62174dab21f670ad6c5d0f243a228f015b", size = 661111, upload-time = "2025-11-24T23:26:04.467Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:54a64f91839ba59008eccf7aad2e93d6e3de688d796f35803235ea1c4898ae1e", size = 636928, upload-time = "2025-11-24T23:26:05.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/fc/9e3486fb2bbe69d4a867c0b76d68542650a7ff1574ca40e84c3111bb0c6e/asyncpg-0.31.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0e0822b1038dc7253b337b0f3f676cadc4ac31b126c5d42691c39691962e403", size = 3424067, upload-time = "2025-11-24T23:26:07.957Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/c6/8c9d076f73f07f995013c791e018a1cd5f31823c2a3187fc8581706aa00f/asyncpg-0.31.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bef056aa502ee34204c161c72ca1f3c274917596877f825968368b2c33f585f4", size = 3518156, upload-time = "2025-11-24T23:26:09.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/3b/60683a0baf50fbc546499cfb53132cb6835b92b529a05f6a81471ab60d0c/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0bfbcc5b7ffcd9b75ab1558f00db2ae07db9c80637ad1b2469c43df79d7a5ae2", size = 3319636, upload-time = "2025-11-24T23:26:11.168Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/dc/8487df0f69bd398a61e1792b3cba0e47477f214eff085ba0efa7eac9ce87/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22bc525ebbdc24d1261ecbf6f504998244d4e3be1721784b5f64664d61fbe602", size = 3472079, upload-time = "2025-11-24T23:26:13.164Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/a1/c5bbeeb8531c05c89135cb8b28575ac2fac618bcb60119ee9696c3faf71c/asyncpg-0.31.0-cp313-cp313-win32.whl", hash = "sha256:f890de5e1e4f7e14023619399a471ce4b71f5418cd67a51853b9910fdfa73696", size = 527606, upload-time = "2025-11-24T23:26:14.78Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/66/b25ccb84a246b470eb943b0107c07edcae51804912b824054b3413995a10/asyncpg-0.31.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc5f2fa9916f292e5c5c8b2ac2813763bcd7f58e130055b4ad8a0531314201ab", size = 596569, upload-time = "2025-11-24T23:26:16.189Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/36/e9450d62e84a13aea6580c83a47a437f26c7ca6fa0f0fd40b6670793ea30/asyncpg-0.31.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f6b56b91bb0ffc328c4e3ed113136cddd9deefdf5f79ab448598b9772831df44", size = 660867, upload-time = "2025-11-24T23:26:17.631Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/4b/1d0a2b33b3102d210439338e1beea616a6122267c0df459ff0265cd5807a/asyncpg-0.31.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:334dec28cf20d7f5bb9e45b39546ddf247f8042a690bff9b9573d00086e69cb5", size = 638349, upload-time = "2025-11-24T23:26:19.689Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/aa/e7f7ac9a7974f08eff9183e392b2d62516f90412686532d27e196c0f0eeb/asyncpg-0.31.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98cc158c53f46de7bb677fd20c417e264fc02b36d901cc2a43bd6cb0dc6dbfd2", size = 3410428, upload-time = "2025-11-24T23:26:21.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/de/bf1b60de3dede5c2731e6788617a512bc0ebd9693eac297ee74086f101d7/asyncpg-0.31.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9322b563e2661a52e3cdbc93eed3be7748b289f792e0011cb2720d278b366ce2", size = 3471678, upload-time = "2025-11-24T23:26:23.627Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/78/fc3ade003e22d8bd53aaf8f75f4be48f0b460fa73738f0391b9c856a9147/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19857a358fc811d82227449b7ca40afb46e75b33eb8897240c3839dd8b744218", size = 3313505, upload-time = "2025-11-24T23:26:25.235Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/e9/73eb8a6789e927816f4705291be21f2225687bfa97321e40cd23055e903a/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ba5f8886e850882ff2c2ace5732300e99193823e8107e2c53ef01c1ebfa1e85d", size = 3434744, upload-time = "2025-11-24T23:26:26.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/4b/f10b880534413c65c5b5862f79b8e81553a8f364e5238832ad4c0af71b7f/asyncpg-0.31.0-cp314-cp314-win32.whl", hash = "sha256:cea3a0b2a14f95834cee29432e4ddc399b95700eb1d51bbc5bfee8f31fa07b2b", size = 532251, upload-time = "2025-11-24T23:26:28.404Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/2d/7aa40750b7a19efa5d66e67fc06008ca0f27ba1bd082e457ad82f59aba49/asyncpg-0.31.0-cp314-cp314-win_amd64.whl", hash = "sha256:04d19392716af6b029411a0264d92093b6e5e8285ae97a39957b9a9c14ea72be", size = 604901, upload-time = "2025-11-24T23:26:30.34Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/fe/b9dfe349b83b9dee28cc42360d2c86b2cdce4cb551a2c2d27e156bcac84d/asyncpg-0.31.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bdb957706da132e982cc6856bb2f7b740603472b54c3ebc77fe60ea3e57e1bd2", size = 702280, upload-time = "2025-11-24T23:26:32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6d11b198111a72f47154fa03b85799f9be63701e068b43f84ac25da0bda9cb31", size = 682931, upload-time = "2025-11-24T23:26:33.572Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/45/6009040da85a1648dd5bc75b3b0a062081c483e75a1a29041ae63a0bf0dc/asyncpg-0.31.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18c83b03bc0d1b23e6230f5bf8d4f217dc9bc08644ce0502a9d91dc9e634a9c7", size = 3581608, upload-time = "2025-11-24T23:26:35.638Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/06/2e3d4d7608b0b2b3adbee0d0bd6a2d29ca0fc4d8a78f8277df04e2d1fd7b/asyncpg-0.31.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e009abc333464ff18b8f6fd146addffd9aaf63e79aa3bb40ab7a4c332d0c5e9e", size = 3498738, upload-time = "2025-11-24T23:26:37.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/aa/7d75ede780033141c51d83577ea23236ba7d3a23593929b32b49db8ed36e/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3b1fbcb0e396a5ca435a8826a87e5c2c2cc0c8c68eb6fadf82168056b0e53a8c", size = 3401026, upload-time = "2025-11-24T23:26:39.423Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/7a/15e37d45e7f7c94facc1e9148c0e455e8f33c08f0b8a0b1deb2c5171771b/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8df714dba348efcc162d2adf02d213e5fab1bd9f557e1305633e851a61814a7a", size = 3429426, upload-time = "2025-11-24T23:26:41.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/d5/71437c5f6ae5f307828710efbe62163974e71237d5d46ebd2869ea052d10/asyncpg-0.31.0-cp314-cp314t-win32.whl", hash = "sha256:1b41f1afb1033f2b44f3234993b15096ddc9cd71b21a42dbd87fc6a57b43d65d", size = 614495, upload-time = "2025-11-24T23:26:42.659Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/d7/8fb3044eaef08a310acfe23dae9a8e2e07d305edc29a53497e52bc76eca7/asyncpg-0.31.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bd4107bb7cdd0e9e65fae66a62afd3a249663b844fa34d479f6d5b3bef9c04c3", size = 706062, upload-time = "2025-11-24T23:26:44.086Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "25.4.0"
|
||||
@@ -196,9 +228,11 @@ name = "birthday-pool-bot"
|
||||
version = "0.0.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "aiogram" },
|
||||
{ name = "alembic" },
|
||||
{ name = "apscheduler" },
|
||||
{ name = "facet" },
|
||||
{ name = "fastapi" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-extra-types", extra = ["phonenumbers"] },
|
||||
{ name = "pydantic-filters" },
|
||||
@@ -207,23 +241,28 @@ dependencies = [
|
||||
{ name = "sqlalchemy" },
|
||||
{ name = "sqlmodel" },
|
||||
{ name = "typer" },
|
||||
{ name = "uvicorn" },
|
||||
{ name = "yarl" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "ruff" },
|
||||
]
|
||||
postgresql = [
|
||||
{ name = "asyncpg" },
|
||||
]
|
||||
sqlite = [
|
||||
{ name = "aiosqlite" },
|
||||
]
|
||||
telegram = [
|
||||
{ name = "aiogram" },
|
||||
{ name = "fastapi" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "aiogram", specifier = ">=3.23.0" },
|
||||
{ name = "alembic", specifier = ">=1.17.2" },
|
||||
{ name = "apscheduler", specifier = ">=3.11.2" },
|
||||
{ name = "facet", specifier = ">=0.10.1" },
|
||||
{ name = "fastapi", specifier = ">=0.124.4" },
|
||||
{ name = "pydantic", specifier = ">=2.12.5" },
|
||||
{ name = "pydantic-extra-types", extras = ["phonenumbers"], specifier = ">=2.10.6" },
|
||||
{ name = "pydantic-filters", git = "https://github.com/OlegYurchik/pydantic-filters?rev=2ca8b822d59feaf5f19f36b570974d314ba5e330" },
|
||||
@@ -232,15 +271,14 @@ requires-dist = [
|
||||
{ name = "sqlalchemy", specifier = ">=2.0.44" },
|
||||
{ name = "sqlmodel", specifier = ">=0.0.27" },
|
||||
{ name = "typer", specifier = ">=0.20.0" },
|
||||
{ name = "uvicorn", specifier = ">=0.38.0" },
|
||||
{ name = "yarl", specifier = ">=1.22.0" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "ruff", specifier = ">=0.14.11" }]
|
||||
postgresql = [{ name = "asyncpg", specifier = ">=0.31.0" }]
|
||||
sqlite = [{ name = "aiosqlite", specifier = ">=0.21.0" }]
|
||||
telegram = [
|
||||
{ name = "aiogram", specifier = ">=3.23.0" },
|
||||
{ name = "fastapi", specifier = ">=0.124.4" },
|
||||
{ name = "uvicorn", specifier = ">=0.38.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
@@ -810,6 +848,32 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.14.11"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d4/77/9a7fe084d268f8855d493e5031ea03fa0af8cc05887f638bf1c4e3363eb8/ruff-0.14.11.tar.gz", hash = "sha256:f6dc463bfa5c07a59b1ff2c3b9767373e541346ea105503b4c0369c520a66958", size = 5993417, upload-time = "2026-01-08T19:11:58.322Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/a6/a4c40a5aaa7e331f245d2dc1ac8ece306681f52b636b40ef87c88b9f7afd/ruff-0.14.11-py3-none-linux_armv6l.whl", hash = "sha256:f6ff2d95cbd335841a7217bdfd9c1d2e44eac2c584197ab1385579d55ff8830e", size = 12951208, upload-time = "2026-01-08T19:12:09.218Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/5c/360a35cb7204b328b685d3129c08aca24765ff92b5a7efedbdd6c150d555/ruff-0.14.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f6eb5c1c8033680f4172ea9c8d3706c156223010b8b97b05e82c59bdc774ee6", size = 13330075, upload-time = "2026-01-08T19:12:02.549Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/9e/0cc2f1be7a7d33cae541824cf3f95b4ff40d03557b575912b5b70273c9ec/ruff-0.14.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2fc34cc896f90080fca01259f96c566f74069a04b25b6205d55379d12a6855e", size = 12257809, upload-time = "2026-01-08T19:12:00.366Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/e5/5faab97c15bb75228d9f74637e775d26ac703cc2b4898564c01ab3637c02/ruff-0.14.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53386375001773ae812b43205d6064dae49ff0968774e6befe16a994fc233caa", size = 12678447, upload-time = "2026-01-08T19:12:13.899Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/33/e9767f60a2bef779fb5855cab0af76c488e0ce90f7bb7b8a45c8a2ba4178/ruff-0.14.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a697737dce1ca97a0a55b5ff0434ee7205943d4874d638fe3ae66166ff46edbe", size = 12758560, upload-time = "2026-01-08T19:11:42.55Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/84/4c6cf627a21462bb5102f7be2a320b084228ff26e105510cd2255ea868e5/ruff-0.14.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6845ca1da8ab81ab1dce755a32ad13f1db72e7fba27c486d5d90d65e04d17b8f", size = 13599296, upload-time = "2026-01-08T19:11:30.371Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/e1/92b5ed7ea66d849f6157e695dc23d5d6d982bd6aa8d077895652c38a7cae/ruff-0.14.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e36ce2fd31b54065ec6f76cb08d60159e1b32bdf08507862e32f47e6dde8bcbf", size = 15048981, upload-time = "2026-01-08T19:12:04.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/df/c1bd30992615ac17c2fb64b8a7376ca22c04a70555b5d05b8f717163cf9f/ruff-0.14.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:590bcc0e2097ecf74e62a5c10a6b71f008ad82eb97b0a0079e85defe19fe74d9", size = 14633183, upload-time = "2026-01-08T19:11:40.069Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/e9/fe552902f25013dd28a5428a42347d9ad20c4b534834a325a28305747d64/ruff-0.14.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53fe71125fc158210d57fe4da26e622c9c294022988d08d9347ec1cf782adafe", size = 14050453, upload-time = "2026-01-08T19:11:37.555Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/93/f36d89fa021543187f98991609ce6e47e24f35f008dfe1af01379d248a41/ruff-0.14.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a35c9da08562f1598ded8470fcfef2afb5cf881996e6c0a502ceb61f4bc9c8a3", size = 13757889, upload-time = "2026-01-08T19:12:07.094Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/9f/c7fb6ecf554f28709a6a1f2a7f74750d400979e8cd47ed29feeaa1bd4db8/ruff-0.14.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0f3727189a52179393ecf92ec7057c2210203e6af2676f08d92140d3e1ee72c1", size = 13955832, upload-time = "2026-01-08T19:11:55.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/a0/153315310f250f76900a98278cf878c64dfb6d044e184491dd3289796734/ruff-0.14.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:eb09f849bd37147a789b85995ff734a6c4a095bed5fd1608c4f56afc3634cde2", size = 12586522, upload-time = "2026-01-08T19:11:35.356Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/2b/a73a2b6e6d2df1d74bf2b78098be1572191e54bec0e59e29382d13c3adc5/ruff-0.14.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c61782543c1231bf71041461c1f28c64b961d457d0f238ac388e2ab173d7ecb7", size = 12724637, upload-time = "2026-01-08T19:11:47.796Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/41/09100590320394401cd3c48fc718a8ba71c7ddb1ffd07e0ad6576b3a3df2/ruff-0.14.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:82ff352ea68fb6766140381748e1f67f83c39860b6446966cff48a315c3e2491", size = 13145837, upload-time = "2026-01-08T19:11:32.87Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/d8/e035db859d1d3edf909381eb8ff3e89a672d6572e9454093538fe6f164b0/ruff-0.14.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:728e56879df4ca5b62a9dde2dd0eb0edda2a55160c0ea28c4025f18c03f86984", size = 13850469, upload-time = "2026-01-08T19:12:11.694Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/02/bb3ff8b6e6d02ce9e3740f4c17dfbbfb55f34c789c139e9cd91985f356c7/ruff-0.14.11-py3-none-win32.whl", hash = "sha256:337c5dd11f16ee52ae217757d9b82a26400be7efac883e9e852646f1557ed841", size = 12851094, upload-time = "2026-01-08T19:11:45.163Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/58/f1/90ddc533918d3a2ad628bc3044cdfc094949e6d4b929220c3f0eb8a1c998/ruff-0.14.11-py3-none-win_amd64.whl", hash = "sha256:f981cea63d08456b2c070e64b79cb62f951aa1305282974d4d5216e6e0178ae6", size = 14001379, upload-time = "2026-01-08T19:11:52.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/1c/1dbe51782c0e1e9cfce1d1004752672d2d4629ea46945d19d731ad772b3b/ruff-0.14.11-py3-none-win_arm64.whl", hash = "sha256:649fb6c9edd7f751db276ef42df1f3df41c38d67d199570ae2a7bd6cbc3590f0", size = 12938644, upload-time = "2026-01-08T19:11:50.027Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
|
||||
Reference in New Issue
Block a user