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
|
RUN pip install uv && apt update && apt install -y git
|
||||||
COPY pyproject.toml uv.lock README.md /app
|
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"]
|
ENTRYPOINT ["uv", "run"]
|
||||||
|
|
||||||
|
|
||||||
FROM core AS app
|
FROM core AS app
|
||||||
|
|
||||||
RUN uv sync --group sqlite
|
RUN uv sync --group sqlite --group postgresql
|
||||||
ENTRYPOINT ["uv", "run", "python", "-m", "birthday_pool_bot"]
|
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
|
# 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
|
payment_data: PaymentData
|
||||||
|
|
||||||
owner: User | None = None
|
owner: User | None = None
|
||||||
|
birthday_user: User | None = None
|
||||||
|
|
||||||
|
|
||||||
class PoolFilter(BaseFilter):
|
class PoolFilter(BaseFilter):
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import uuid
|
from typing import Any
|
||||||
from datetime import timedelta
|
|
||||||
from typing import AsyncContextManager, AsyncGenerator, Protocol
|
|
||||||
|
|
||||||
from birthday_pool_bot.dto import Pool, User
|
import pathlib
|
||||||
|
from datetime import timedelta
|
||||||
|
from typing import AsyncContextManager, Generator, Protocol
|
||||||
|
|
||||||
|
|
||||||
class MessengerInterface(Protocol):
|
class MessengerInterface(Protocol):
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import asyncio
|
|||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
|
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||||
from .service import NotificationsService
|
from .service import NotificationsService
|
||||||
from .settings import NotificationsSettings
|
from .settings import NotificationsSettings
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from aiogram.enums import ParseMode
|
|||||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
|
|
||||||
|
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||||
from .settings import NotificationsSettings
|
from .settings import NotificationsSettings
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import contextvars
|
import contextvars
|
||||||
from contextlib import asynccontextmanager, contextmanager
|
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 pydantic_filters.drivers.sqlalchemy import append_to_statement
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from sqlalchemy.exc import IntegrityError
|
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 import delete, insert, select, update
|
||||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
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")
|
DTOType = TypeVar("DTOType")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from .migrator import Migrator
|
|||||||
def callback(ctx: typer.Context):
|
def callback(ctx: typer.Context):
|
||||||
ctx.obj = ctx.obj or {}
|
ctx.obj = ctx.obj or {}
|
||||||
|
|
||||||
settings = ctx.obj["settings"]
|
settings: Settings = ctx.obj["settings"]
|
||||||
ctx.obj["migrator"] = Migrator(settings=settings.repository)
|
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("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
|
||||||
sa.Column("birthday", sa.Date(), nullable=True),
|
sa.Column("birthday", sa.Date(), nullable=True),
|
||||||
sa.Column("phone", sqlmodel.sql.sqltypes.AutoString(), 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.Column("gift_payment_data", sa.JSON(), nullable=True),
|
||||||
sa.PrimaryKeyConstraint("id"),
|
sa.PrimaryKeyConstraint("id"),
|
||||||
sa.UniqueConstraint("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 sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
from birthday_pool_bot.dto import Pool, PoolFilter
|
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})
|
filter_ = PoolFilter(birthday_user_id={birthday_user_id})
|
||||||
return await self.get_items_count(filter_=filter_)
|
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})
|
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(
|
async def get_pool_by_id(
|
||||||
self,
|
self,
|
||||||
pool_id: uuid.UUID,
|
pool_id: uuid.UUID,
|
||||||
with_owner: bool = False,
|
with_owner: bool = False,
|
||||||
|
with_birthday_user: bool = False,
|
||||||
) -> Pool | None:
|
) -> Pool | None:
|
||||||
filter_ = PoolFilter(id={pool_id})
|
filter_ = PoolFilter(id={pool_id})
|
||||||
pagination = OffsetPagination(limit=1)
|
pagination = OffsetPagination(limit=1)
|
||||||
options = []
|
options = []
|
||||||
if with_owner:
|
if with_owner:
|
||||||
options.append(joinedload(DBPool.owner))
|
options.append(joinedload(DBPool.owner))
|
||||||
|
if with_birthday_user:
|
||||||
|
options.append(joinedload(DBPool.birthday_user))
|
||||||
|
|
||||||
pools_generator = self.get_items(
|
pools_generator = self.get_items(
|
||||||
filter_=filter_,
|
filter_=filter_,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
from typing import AsyncGenerator, Iterable
|
||||||
|
|
||||||
from pydantic_filters import BasePagination, OffsetPagination
|
from pydantic_filters import BasePagination, OffsetPagination
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import uuid
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Container, Sequence, TypeVar
|
from typing import Container, Sequence, TypeVar
|
||||||
|
|
||||||
from pydantic_filters import OffsetPagination
|
from pydantic_filters import BasePagination, OffsetPagination
|
||||||
from sqlalchemy import Column, func, inspect, select
|
from sqlalchemy import Column, func, inspect, or_, select, update
|
||||||
from sqlmodel import SQLModel
|
from sqlmodel import SQLModel
|
||||||
|
|
||||||
from birthday_pool_bot.dto import User, UserFilter
|
from birthday_pool_bot.dto import User, UserFilter
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import uuid
|
import uuid
|
||||||
import enum
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Self, List
|
from typing import Any, Self
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
from pydantic import BaseModel
|
||||||
from sqlmodel import SQLModel, Field, Relationship
|
from sqlmodel import SQLModel, Field, Relationship
|
||||||
|
|
||||||
from birthday_pool_bot.dto import (
|
from birthday_pool_bot.dto import (
|
||||||
BankEnum,
|
|
||||||
PaymentData as DTOPaymentData,
|
PaymentData as DTOPaymentData,
|
||||||
Pool as DTOPool,
|
Pool as DTOPool,
|
||||||
Subscription as DTOSubscription,
|
Subscription as DTOSubscription,
|
||||||
@@ -46,7 +45,10 @@ class User(BaseSQLModel, table=True):
|
|||||||
name: str | None = Field(nullable=True)
|
name: str | None = Field(nullable=True)
|
||||||
birthday: date | None = Field(nullable=True)
|
birthday: date | None = Field(nullable=True)
|
||||||
phone: str | None = Field(default=None, 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(
|
gift_payment_data: dict | None = Field(
|
||||||
sa_column=sa.Column(sa.JSON, nullable=True),
|
sa_column=sa.Column(sa.JSON, nullable=True),
|
||||||
default_factory=dict,
|
default_factory=dict,
|
||||||
@@ -118,6 +120,12 @@ class Pool(BaseSQLModel, table=True):
|
|||||||
"lazy": None,
|
"lazy": None,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
birthday_user: User = Relationship(
|
||||||
|
sa_relationship_kwargs={
|
||||||
|
"primaryjoin": "User.id == Pool.birthday_user_id",
|
||||||
|
"lazy": None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_item(cls, item: DTOPool) -> Self:
|
def from_item(cls, item: DTOPool) -> Self:
|
||||||
@@ -128,6 +136,11 @@ class Pool(BaseSQLModel, table=True):
|
|||||||
description=item.description,
|
description=item.description,
|
||||||
payment_data=item.payment_data.model_dump_json(),
|
payment_data=item.payment_data.model_dump_json(),
|
||||||
owner=None if item.owner is None else DTOUser.from_item(item.owner),
|
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:
|
def to_item(self) -> DTOPool:
|
||||||
@@ -137,7 +150,8 @@ class Pool(BaseSQLModel, table=True):
|
|||||||
birthday_user_id=self.birthday_user_id,
|
birthday_user_id=self.birthday_user_id,
|
||||||
description=self.description,
|
description=self.description,
|
||||||
payment_data=DTOPaymentData.model_validate_json(self.payment_data),
|
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__ = (
|
__all__ = (
|
||||||
# cli
|
# cli
|
||||||
"get_cli",
|
"get_cli",
|
||||||
|
# fabric
|
||||||
|
"get_telegram_bot_service",
|
||||||
# settings
|
# settings
|
||||||
"TelegramBotSettings",
|
"TelegramBotSettings",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import facet
|
|||||||
from aiogram.fsm.storage.memory import MemoryStorage
|
from aiogram.fsm.storage.memory import MemoryStorage
|
||||||
|
|
||||||
from birthday_pool_bot.repositories import RepositoriesContainer
|
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||||
|
from .settings import TelegramBotSettings
|
||||||
from .ui import setup_dispatcher
|
from .ui import setup_dispatcher
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ def get_telegram_bot_service(
|
|||||||
repositories_container: RepositoriesContainer,
|
repositories_container: RepositoriesContainer,
|
||||||
) -> BaseTelegramBotService:
|
) -> BaseTelegramBotService:
|
||||||
match settings.method:
|
match settings.method:
|
||||||
case TelegramBotMethodEnum.POLLING:
|
case TelegramBotMethodEnum.POLLING.value:
|
||||||
return TelegramBotPollingService(
|
return TelegramBotPollingService(
|
||||||
settings=settings,
|
settings=settings,
|
||||||
repositories_container=repositories_container,
|
repositories_container=repositories_container,
|
||||||
)
|
)
|
||||||
case TelegramBotMethodEnum.WEBHOOK:
|
case TelegramBotMethodEnum.WEBHOOK.value:
|
||||||
return TelegramBotWebhookService(
|
return TelegramBotWebhookService(
|
||||||
settings=settings,
|
settings=settings,
|
||||||
repositories_container=repositories_container,
|
repositories_container=repositories_container,
|
||||||
)
|
)
|
||||||
case _:
|
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):
|
class TelegramBotPollingService(BaseTelegramBotService):
|
||||||
async def listen_events(self):
|
async def listen_events(self):
|
||||||
|
await self._bot.delete_webhook()
|
||||||
await self._dispatcher._polling( # pylint: disable=protected-access
|
await self._dispatcher._polling( # pylint: disable=protected-access
|
||||||
bot=self._bot,
|
bot=self._bot,
|
||||||
polling_timeout=self._settings.timeout,
|
polling_timeout=self._settings.timeout,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from birthday_pool_bot.telegram_bot.settings import TelegramBotSettings
|
|||||||
|
|
||||||
class TelegramBotPollingSettings(TelegramBotSettings):
|
class TelegramBotPollingSettings(TelegramBotSettings):
|
||||||
method: Literal[TelegramBotMethodEnum.POLLING.value] = (
|
method: Literal[TelegramBotMethodEnum.POLLING.value] = (
|
||||||
TelegramBotMethodEnum.POLLING
|
TelegramBotMethodEnum.POLLING.value
|
||||||
)
|
)
|
||||||
|
|
||||||
timeout: PositiveInt = 10 # in seconds
|
timeout: PositiveInt = 10 # in seconds
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import enum
|
import enum
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from aiogram.filters.callback_data import CallbackData
|
from aiogram.filters.callback_data import CallbackData
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
|
|
||||||
class PaginatorCallbackData(CallbackData, prefix=""):
|
class PaginatorCallbackData(CallbackData, prefix=""):
|
||||||
@@ -18,7 +16,7 @@ class SubscriptionsCallbackData(PaginatorCallbackData, prefix="subscriptions"):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AddSubscriptionCallbackData(CallbackData, prefix="subscription_add"):
|
class NewSubscriptionCallbackData(CallbackData, prefix="new_subscription"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +25,7 @@ class ConfirmAnswerEnum(str, enum.Enum):
|
|||||||
NO = "no"
|
NO = "no"
|
||||||
|
|
||||||
|
|
||||||
class AddSubscriptionConfirmCallbackData(CallbackData, prefix="subscription_add_confirm"):
|
class NewSubscriptionConfirmCallbackData(CallbackData, prefix="new_subscription_confirm"):
|
||||||
answer: ConfirmAnswerEnum
|
answer: ConfirmAnswerEnum
|
||||||
|
|
||||||
|
|
||||||
@@ -43,5 +41,19 @@ class SubscriptionCallbackData(CallbackData, prefix="subscription"):
|
|||||||
action: SubscriptionActionEnum = SubscriptionActionEnum.SHOW
|
action: SubscriptionActionEnum = SubscriptionActionEnum.SHOW
|
||||||
|
|
||||||
|
|
||||||
class AddSubscriptionPoolsCallbackData(PaginatorCallbackData, prefix="subscription_add_pool"):
|
class PoolsCallbackData(PaginatorCallbackData, prefix="pools"):
|
||||||
to_user_id: uuid.UUID
|
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
|
import aiogram
|
||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
from aiogram_dialog import DialogManager
|
|
||||||
from birthday_pool_bot.repositories import RepositoriesContainer
|
from birthday_pool_bot.repositories import RepositoriesContainer
|
||||||
|
|
||||||
from . import constants, handlers
|
from . import constants, handlers
|
||||||
from .callback_data import (
|
from .callback_data import (
|
||||||
AddSubscriptionCallbackData,
|
|
||||||
AddSubscriptionConfirmCallbackData,
|
|
||||||
ConfirmAnswerEnum,
|
ConfirmAnswerEnum,
|
||||||
MenuCallbackData,
|
MenuCallbackData,
|
||||||
|
NewSubscriptionCallbackData,
|
||||||
|
NewSubscriptionConfirmCallbackData,
|
||||||
|
PoolActionEnum,
|
||||||
|
PoolCallbackData,
|
||||||
|
PoolsBackCallbackData,
|
||||||
|
PoolsCallbackData,
|
||||||
SubscriptionActionEnum,
|
SubscriptionActionEnum,
|
||||||
SubscriptionCallbackData,
|
SubscriptionCallbackData,
|
||||||
SubscriptionsCallbackData,
|
SubscriptionsCallbackData,
|
||||||
@@ -16,12 +19,12 @@ from .callback_data import (
|
|||||||
from .middlewares import (
|
from .middlewares import (
|
||||||
AuthMiddleware,
|
AuthMiddleware,
|
||||||
DependsMiddleware,
|
DependsMiddleware,
|
||||||
TypingMiddleware,
|
# TypingMiddleware,
|
||||||
)
|
)
|
||||||
from .states import (
|
from .states import (
|
||||||
AddSubscriptionPoolState,
|
|
||||||
AddSubscriptionState,
|
|
||||||
MenuState,
|
MenuState,
|
||||||
|
NewSubscriptionPoolState,
|
||||||
|
NewSubscriptionState,
|
||||||
SetProfileBirthdayState,
|
SetProfileBirthdayState,
|
||||||
SetProfileGiftPaymentDataState,
|
SetProfileGiftPaymentDataState,
|
||||||
SetProfileNameState,
|
SetProfileNameState,
|
||||||
@@ -33,7 +36,7 @@ def setup_dispatcher(
|
|||||||
dispatcher: aiogram.Dispatcher,
|
dispatcher: aiogram.Dispatcher,
|
||||||
repositories_container: RepositoriesContainer,
|
repositories_container: RepositoriesContainer,
|
||||||
):
|
):
|
||||||
typing_middleware = TypingMiddleware()
|
# typing_middleware = TypingMiddleware()
|
||||||
auth_middleware = AuthMiddleware(users_repository=repositories_container.users)
|
auth_middleware = AuthMiddleware(users_repository=repositories_container.users)
|
||||||
users_repository_middleware = DependsMiddleware(
|
users_repository_middleware = DependsMiddleware(
|
||||||
name="users_repository",
|
name="users_repository",
|
||||||
@@ -175,9 +178,9 @@ def setup_router(router: aiogram.Router) -> aiogram.Router:
|
|||||||
SubscriptionsCallbackData.filter(),
|
SubscriptionsCallbackData.filter(),
|
||||||
)
|
)
|
||||||
router.callback_query.register(
|
router.callback_query.register(
|
||||||
handlers.add_subscription_callback_handler,
|
handlers.new_subscription_callback_handler,
|
||||||
MenuState.SUBSCRIPTIONS,
|
MenuState.SUBSCRIPTIONS,
|
||||||
AddSubscriptionCallbackData.filter(),
|
NewSubscriptionCallbackData.filter(),
|
||||||
)
|
)
|
||||||
router.callback_query.register(
|
router.callback_query.register(
|
||||||
handlers.menu_callback_handler,
|
handlers.menu_callback_handler,
|
||||||
@@ -203,107 +206,132 @@ def setup_router(router: aiogram.Router) -> aiogram.Router:
|
|||||||
|
|
||||||
### Add new subscription
|
### Add new subscription
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.add_subscription_message_handler,
|
handlers.new_subscription_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_PHONE,
|
NewSubscriptionState.WAITING_FOR_PHONE,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_user_message_handler,
|
handlers.set_new_subscription_user_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_PHONE,
|
NewSubscriptionState.WAITING_FOR_PHONE,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_user_message_handler,
|
handlers.ask_new_subscription_user_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_DATE,
|
NewSubscriptionState.WAITING_FOR_DATE,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_user_birthday_message_handler,
|
handlers.set_new_subscription_user_birthday_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_DATE,
|
NewSubscriptionState.WAITING_FOR_DATE,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_user_message_handler,
|
handlers.ask_new_subscription_user_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_NAME,
|
NewSubscriptionState.WAITING_FOR_NAME,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_name_message_handler,
|
handlers.set_new_subscription_name_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_NAME,
|
NewSubscriptionState.WAITING_FOR_NAME,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_pool_description_message_handler,
|
handlers.ask_new_subscription_pool_description_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
|
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
|
||||||
aiogram.F.text == constants.CREATE_POOL_BUTTON,
|
aiogram.F.text == constants.CREATE_POOL_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.show_add_subscription_pools_message_handler,
|
handlers.show_new_subscription_choosing_pools_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
|
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
|
||||||
aiogram.F.text == constants.JOIN_EXISTING_POOL_BUTTON,
|
aiogram.F.text == constants.JOIN_EXISTING_POOL_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_confirmation_message_handler,
|
handlers.ask_new_subscription_confirmation_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
|
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
|
||||||
aiogram.F.text == constants.DECLINE_POOL_BUTTON,
|
aiogram.F.text == constants.DECLINE_POOL_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_name_message_handler,
|
handlers.ask_new_subscription_name_message_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_POOL_DECISION,
|
NewSubscriptionState.WAITING_FOR_POOL_DECISION,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.callback_query.register(
|
router.callback_query.register(
|
||||||
handlers.confirm_add_subscription_callback_handler,
|
handlers.confirm_new_subscription_callback_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_CONFIRMATION,
|
NewSubscriptionState.WAITING_FOR_CONFIRMATION,
|
||||||
AddSubscriptionConfirmCallbackData.filter(
|
NewSubscriptionConfirmCallbackData.filter(
|
||||||
aiogram.F.answer == ConfirmAnswerEnum.YES,
|
aiogram.F.answer == ConfirmAnswerEnum.YES,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
router.callback_query.register(
|
router.callback_query.register(
|
||||||
handlers.subscriptions_callback_handler,
|
handlers.subscriptions_callback_handler,
|
||||||
AddSubscriptionState.WAITING_FOR_CONFIRMATION,
|
NewSubscriptionState.WAITING_FOR_CONFIRMATION,
|
||||||
AddSubscriptionConfirmCallbackData.filter(
|
NewSubscriptionConfirmCallbackData.filter(
|
||||||
aiogram.F.answer == ConfirmAnswerEnum.NO,
|
aiogram.F.answer == ConfirmAnswerEnum.NO,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
#### Add new subscription pool
|
#### Add new subscription pool
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_pool_payment_phone_message_handler,
|
handlers.ask_new_subscription_pool_payment_phone_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
|
NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
|
||||||
aiogram.F.text == constants.SKIP_BUTTON,
|
aiogram.F.text == constants.SKIP_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_pool_decision_message_handler,
|
handlers.ask_new_subscription_pool_decision_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
|
NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_pool_description_message_handler,
|
handlers.set_new_subscription_pool_description_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
|
NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_pool_payment_data_from_profile_message_handler,
|
handlers.set_new_subscription_pool_payment_data_from_profile_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
|
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
|
||||||
aiogram.F.text == constants.USE_PROFILE_GIFT_PAYMENT_DATA,
|
aiogram.F.text == constants.USE_PROFILE_GIFT_PAYMENT_DATA,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.ask_add_subscription_pool_description_message_handler,
|
handlers.ask_new_subscription_pool_description_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
|
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_pool_payment_phone_message_handler,
|
handlers.set_new_subscription_pool_payment_phone_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
|
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_pool_payment_phone_message_handler,
|
handlers.set_new_subscription_pool_payment_phone_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
|
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
|
||||||
aiogram.F.text == constants.BACK_BUTTON,
|
aiogram.F.text == constants.BACK_BUTTON,
|
||||||
)
|
)
|
||||||
router.message.register(
|
router.message.register(
|
||||||
handlers.set_add_subscription_pool_payment_bank_message_handler,
|
handlers.set_new_subscription_pool_payment_bank_message_handler,
|
||||||
AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
|
NewSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK,
|
||||||
)
|
)
|
||||||
|
|
||||||
#### Choose pool for subscription
|
#### 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
|
# Fallback
|
||||||
router.message.register(handlers.fallback_message_handler)
|
router.message.register(handlers.fallback_message_handler)
|
||||||
|
|||||||
@@ -1,21 +1,13 @@
|
|||||||
import asyncio
|
from aiogram import types
|
||||||
import uuid
|
|
||||||
|
|
||||||
from aiogram import types, F, Router
|
|
||||||
from aiogram.enums import MessageOriginType, ParseMode
|
from aiogram.enums import MessageOriginType, ParseMode
|
||||||
from aiogram.filters import Command
|
|
||||||
from aiogram.fsm.context import FSMContext
|
from aiogram.fsm.context import FSMContext
|
||||||
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
|
|
||||||
from pydantic_core import PydanticCustomError
|
from pydantic_core import PydanticCustomError
|
||||||
from pydantic_filters import PagePagination
|
|
||||||
from pydantic_extra_types.phone_numbers import PhoneNumber
|
from pydantic_extra_types.phone_numbers import PhoneNumber
|
||||||
|
|
||||||
from birthday_pool_bot.dto import (
|
from birthday_pool_bot.dto import (
|
||||||
BankEnum,
|
|
||||||
PaymentData,
|
PaymentData,
|
||||||
Pool,
|
Pool,
|
||||||
Subscription,
|
Subscription,
|
||||||
SubscriptionFilter,
|
|
||||||
User,
|
User,
|
||||||
)
|
)
|
||||||
from birthday_pool_bot.repositories.repositories import (
|
from birthday_pool_bot.repositories.repositories import (
|
||||||
@@ -24,18 +16,11 @@ from birthday_pool_bot.repositories.repositories import (
|
|||||||
UsersRepository,
|
UsersRepository,
|
||||||
)
|
)
|
||||||
from . import constants, logic
|
from . import constants, logic
|
||||||
from .callback_data import (
|
from .callback_data import PoolCallbackData, SubscriptionCallbackData
|
||||||
AddSubscriptionCallbackData,
|
|
||||||
AddSubscriptionConfirmCallbackData,
|
|
||||||
ConfirmAnswerEnum,
|
|
||||||
MenuCallbackData,
|
|
||||||
SubscriptionCallbackData,
|
|
||||||
SubscriptionsCallbackData,
|
|
||||||
)
|
|
||||||
from .exceptions import FlowInternalError
|
from .exceptions import FlowInternalError
|
||||||
from .states import (
|
from .states import (
|
||||||
AddSubscriptionPoolState,
|
NewSubscriptionPoolState,
|
||||||
AddSubscriptionState,
|
NewSubscriptionState,
|
||||||
MenuState,
|
MenuState,
|
||||||
SetProfileBirthdayState,
|
SetProfileBirthdayState,
|
||||||
SetProfileGiftPaymentDataState,
|
SetProfileGiftPaymentDataState,
|
||||||
@@ -322,31 +307,31 @@ async def delete_subscription_callback(
|
|||||||
await state.set_state(MenuState.SUBSCRIPTIONS)
|
await state.set_state(MenuState.SUBSCRIPTIONS)
|
||||||
|
|
||||||
|
|
||||||
async def add_subscription_message_handler(
|
async def new_subscription_message_handler(
|
||||||
message: types.Message,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
|
|
||||||
|
|
||||||
async def add_subscription_callback_handler(
|
async def new_subscription_callback_handler(
|
||||||
callback_query: types.CallbackQuery,
|
callback_query: types.CallbackQuery,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_user(callback_query=callback_query)
|
await logic.ask_new_subscription_user(callback_query=callback_query)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
user: User,
|
user: User,
|
||||||
@@ -370,15 +355,15 @@ async def set_add_subscription_user_message_handler(
|
|||||||
await message.reply(
|
await message.reply(
|
||||||
text="Пользователь скрыл свои данные, попробуйте отправить номер телефона или его контакт",
|
text="Пользователь скрыл свои данные, попробуйте отправить номер телефона или его контакт",
|
||||||
)
|
)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
if message.forward_origin.type != MessageOriginType.USER:
|
if message.forward_origin.type != MessageOriginType.USER:
|
||||||
await message.reply(
|
await message.reply(
|
||||||
text="Это сообщение не от пользователя, попробуйте ещё раз",
|
text="Это сообщение не от пользователя, попробуйте ещё раз",
|
||||||
)
|
)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
user_name = get_telegram_user_full_name(message.forward_origin.sender_user)
|
user_name = get_telegram_user_full_name(message.forward_origin.sender_user)
|
||||||
user_telegram_id = message.forward_origin.sender_user.id
|
user_telegram_id = message.forward_origin.sender_user.id
|
||||||
@@ -390,8 +375,8 @@ async def set_add_subscription_user_message_handler(
|
|||||||
try:
|
try:
|
||||||
PhoneNumber._validate(user_phone, None)
|
PhoneNumber._validate(user_phone, None)
|
||||||
except PydanticCustomError:
|
except PydanticCustomError:
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
subscription_user = await users_repository.get_user_by_phone(phone=user_phone)
|
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:
|
if subscription_user.id == user.id:
|
||||||
await message.reply("Нельзя подписаться на самого себя")
|
await message.reply("Нельзя подписаться на самого себя")
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
async with subscriptions_repository.transaction():
|
async with subscriptions_repository.transaction():
|
||||||
@@ -418,8 +403,8 @@ async def set_add_subscription_user_message_handler(
|
|||||||
|
|
||||||
if subscription is not None:
|
if subscription is not None:
|
||||||
await message.reply(text="У вас уже есть подписка на этого человека")
|
await message.reply(text="У вас уже есть подписка на этого человека")
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
await state.update_data(
|
await state.update_data(
|
||||||
@@ -427,65 +412,65 @@ async def set_add_subscription_user_message_handler(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if subscription_user.birthday is None:
|
if subscription_user.birthday is None:
|
||||||
await logic.ask_add_subscription_user_birthday(message=message)
|
await logic.ask_new_subscription_user_birthday(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_DATE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_DATE)
|
||||||
return
|
return
|
||||||
|
|
||||||
await logic.ask_add_subscription_name(
|
await logic.ask_new_subscription_name(
|
||||||
message=message,
|
message=message,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
subscription_user_id=subscription_user.id,
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_user_birthday(message=message)
|
await logic.ask_new_subscription_user_birthday(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_DATE)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
users_repository: UsersRepository,
|
users_repository: UsersRepository,
|
||||||
):
|
):
|
||||||
birthday = parse_date(message=message)
|
birthday = parse_date(message=message)
|
||||||
if birthday is None:
|
if birthday is None:
|
||||||
await logic.ask_add_subscription_user_birthday(message=message)
|
await logic.ask_new_subscription_user_birthday(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_DATE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_DATE)
|
||||||
return
|
return
|
||||||
|
|
||||||
state_data = await state.get_data()
|
state_data = await state.get_data()
|
||||||
subscription_user_id = state_data.get("subscription_user_id")
|
subscription_user_id = state_data.get("subscription_user_id")
|
||||||
if subscription_user_id is None:
|
if subscription_user_id is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
async with users_repository.transaction():
|
async with users_repository.transaction():
|
||||||
subscription_user = await users_repository.get_user_by_id(user_id=subscription_user_id)
|
subscription_user = await users_repository.get_user_by_id(user_id=subscription_user_id)
|
||||||
if subscription_user is None:
|
if subscription_user is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
subscription_user.birthday = birthday
|
subscription_user.birthday = birthday
|
||||||
await users_repository.update_user(user=subscription_user)
|
await users_repository.update_user(user=subscription_user)
|
||||||
|
|
||||||
await logic.ask_add_subscription_name(
|
await logic.ask_new_subscription_name(
|
||||||
message=message,
|
message=message,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
subscription_user_id=subscription_user.id,
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
users_repository: UsersRepository,
|
users_repository: UsersRepository,
|
||||||
@@ -494,26 +479,26 @@ async def ask_add_subscription_name_message_handler(
|
|||||||
subscription_user_id = state_data.get("subscription_user_id")
|
subscription_user_id = state_data.get("subscription_user_id")
|
||||||
if subscription_user_id is None:
|
if subscription_user_id is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await logic.ask_add_subscription_name(
|
await logic.ask_new_subscription_name(
|
||||||
message=message,
|
message=message,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
subscription_user_id=subscription_user_id,
|
subscription_user_id=subscription_user_id,
|
||||||
)
|
)
|
||||||
except FlowInternalError:
|
except FlowInternalError:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
user: User,
|
user: User,
|
||||||
@@ -525,29 +510,29 @@ async def set_add_subscription_name_message_handler(
|
|||||||
subscription_user_id = state_data.get("subscription_user_id")
|
subscription_user_id = state_data.get("subscription_user_id")
|
||||||
if subscription_user_id is None:
|
if subscription_user_id is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
async with users_repository.transaction():
|
async with users_repository.transaction():
|
||||||
subscription_user = await users_repository.get_user_by_id(user_id=subscription_user_id)
|
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:
|
if subscription_user is None or subscription_user.birthday is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
await state.update_data(subscription_name=message.text)
|
await state.update_data(subscription_name=message.text)
|
||||||
await logic.ask_add_subscription_pool_decision(
|
await logic.ask_new_subscription_pool_decision(
|
||||||
message=message,
|
message=message,
|
||||||
pools_repository=pools_repository,
|
pools_repository=pools_repository,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
subscription_user_id=subscription_user_id,
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
pools_repository: PoolsRepository,
|
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")
|
subscription_user_id = state_data.get("subscription_user_id")
|
||||||
if subscription_user_id is None:
|
if subscription_user_id is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await logic.ask_add_subscription_pool_decision(
|
await logic.ask_new_subscription_pool_decision(
|
||||||
message=message,
|
message=message,
|
||||||
pools_repository=pools_repository,
|
pools_repository=pools_repository,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
@@ -570,72 +555,235 @@ async def ask_add_subscription_pool_decision_message_handler(
|
|||||||
)
|
)
|
||||||
except FlowInternalError:
|
except FlowInternalError:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
user: User,
|
user: User,
|
||||||
|
users_repository: UsersRepository,
|
||||||
pools_repository: PoolsRepository,
|
pools_repository: PoolsRepository,
|
||||||
):
|
):
|
||||||
state_data = await state.get_data()
|
state_data = await state.get_data()
|
||||||
subscription_user_id = state_data.get("subscription_user_id")
|
subscription_user_id = state_data.get("subscription_user_id")
|
||||||
if subscription_user_id is None:
|
if subscription_user_id is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await logic.show_add_subscription_pools(
|
await logic.show_new_subscription_choosing_pools(
|
||||||
user=user,
|
user=user,
|
||||||
|
users_repository=users_repository,
|
||||||
pools_repository=pools_repository,
|
pools_repository=pools_repository,
|
||||||
|
subscription_user_id=subscription_user_id,
|
||||||
message=message,
|
message=message,
|
||||||
)
|
)
|
||||||
except FlowInternalError:
|
except FlowInternalError:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
await logic.ask_add_subscription_pool_description(message=message)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_CHOOSE_POOL)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
|
|
||||||
|
|
||||||
|
|
||||||
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_pool_description(message=message)
|
await logic.ask_new_subscription_pool_description(message=message)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
description = message.text
|
description = message.text
|
||||||
await state.update_data(subscription_pool_description=description)
|
await state.update_data(subscription_pool_description=description)
|
||||||
|
|
||||||
await logic.ask_add_subscription_pool_payment_phone(message=message)
|
await logic.ask_new_subscription_pool_payment_phone(message=message)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
user: User,
|
user: User,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_pool_payment_phone(message=message, user=user)
|
await logic.ask_new_subscription_pool_payment_phone(message=message, user=user)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
@@ -646,8 +794,8 @@ async def set_add_subscription_pool_payment_phone_message_handler(
|
|||||||
phone_number = message.text
|
phone_number = message.text
|
||||||
else:
|
else:
|
||||||
await message.reply(text="Некорректный номер телефона, попробуйте ещё раз")
|
await message.reply(text="Некорректный номер телефона, попробуйте ещё раз")
|
||||||
await logic.ask_add_subscription_pool_payment_phone(message=message)
|
await logic.ask_new_subscription_pool_payment_phone(message=message)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -656,16 +804,16 @@ async def set_add_subscription_pool_payment_phone_message_handler(
|
|||||||
await message.reply(
|
await message.reply(
|
||||||
text="Некорректный номер телефона, попробуйте ещё раз",
|
text="Некорректный номер телефона, попробуйте ещё раз",
|
||||||
)
|
)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
await state.update_data(subscription_pool_phone=phone_number)
|
await state.update_data(subscription_pool_phone=phone_number)
|
||||||
|
|
||||||
await logic.ask_add_subscription_pool_payment_bank(message=message)
|
await logic.ask_new_subscription_pool_payment_bank(message=message)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
user: User,
|
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:
|
if user.gift_payment_data is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_pool_payment_phone(message=message, user=user)
|
await logic.ask_new_subscription_pool_payment_phone(message=message, user=user)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_PAYMENT_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
state_data = await state.get_data()
|
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")
|
subscription_pool_description = state_data.get("subscription_pool_description")
|
||||||
if not all((subscription_user_id, subscription_name)):
|
if not all((subscription_user_id, subscription_name)):
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
await state.update_data(
|
await state.update_data(
|
||||||
subscription_pool_phone=user.gift_payment_data.phone,
|
subscription_pool_phone=user.gift_payment_data.phone,
|
||||||
subscription_pool_bank=user.gift_payment_data.bank,
|
subscription_pool_bank=user.gift_payment_data.bank,
|
||||||
)
|
)
|
||||||
await logic.ask_add_subscription_confirmation(
|
await logic.ask_new_subscription_confirmation(
|
||||||
message=message,
|
message=message,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
pools_repository=pools_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_phone=user.gift_payment_data.phone,
|
||||||
subscription_pool_bank=user.gift_payment_data.bank,
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
):
|
):
|
||||||
await logic.ask_add_subscription_pool_payment_bank(message=message)
|
await logic.ask_new_subscription_pool_payment_bank(message=message)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_PAYMENT_BANK)
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
users_repository: UsersRepository,
|
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")
|
subscription_pool_phone = state_data.get("subscription_pool_phone")
|
||||||
if not all((subscription_user_id, subscription_name)):
|
if not all((subscription_user_id, subscription_name)):
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
if subscription_pool_phone is None:
|
if subscription_pool_phone is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_pool_decision(message=message)
|
await logic.ask_new_subscription_pool_decision(message=message)
|
||||||
await state.set_state(AddSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
|
await state.set_state(NewSubscriptionPoolState.WAITING_FOR_DESCRIPTION)
|
||||||
return
|
return
|
||||||
|
|
||||||
async with users_repository.transaction():
|
async with users_repository.transaction():
|
||||||
@@ -741,8 +889,8 @@ async def set_add_subscription_pool_payment_bank_message_handler(
|
|||||||
)
|
)
|
||||||
if subscription_user is None:
|
if subscription_user is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
bank_name = message.text
|
bank_name = message.text
|
||||||
@@ -754,7 +902,7 @@ async def set_add_subscription_pool_payment_bank_message_handler(
|
|||||||
bank = constants.BANKS_MAP[bank_name]
|
bank = constants.BANKS_MAP[bank_name]
|
||||||
await state.update_data(subscription_pool_bank=bank)
|
await state.update_data(subscription_pool_bank=bank)
|
||||||
|
|
||||||
await logic.ask_add_subscription_confirmation(
|
await logic.ask_new_subscription_confirmation(
|
||||||
message=message,
|
message=message,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
pools_repository=pools_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_phone=subscription_pool_phone,
|
||||||
subscription_pool_bank=bank,
|
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,
|
message: types.Message,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
users_repository: UsersRepository,
|
users_repository: UsersRepository,
|
||||||
@@ -782,8 +930,8 @@ async def ask_add_subscription_confirmation_message_handler(
|
|||||||
subscription_pool_bank = state_data.get("subscription_pool_bank")
|
subscription_pool_bank = state_data.get("subscription_pool_bank")
|
||||||
if not all((subscription_user_id, subscription_name)):
|
if not all((subscription_user_id, subscription_name)):
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
async with users_repository.transaction():
|
async with users_repository.transaction():
|
||||||
@@ -792,12 +940,12 @@ async def ask_add_subscription_confirmation_message_handler(
|
|||||||
)
|
)
|
||||||
if subscription_user is None:
|
if subscription_user is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await logic.ask_add_subscription_confirmation(
|
await logic.ask_new_subscription_confirmation(
|
||||||
message=message,
|
message=message,
|
||||||
users_repository=users_repository,
|
users_repository=users_repository,
|
||||||
pools_repository=pools_repository,
|
pools_repository=pools_repository,
|
||||||
@@ -810,14 +958,14 @@ async def ask_add_subscription_confirmation_message_handler(
|
|||||||
)
|
)
|
||||||
except FlowInternalError:
|
except FlowInternalError:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await message.reply(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
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,
|
callback_query: types.CallbackQuery,
|
||||||
state: FSMContext,
|
state: FSMContext,
|
||||||
user: User,
|
user: User,
|
||||||
@@ -833,9 +981,9 @@ async def confirm_add_subscription_callback_handler(
|
|||||||
subscription_pool_phone = state_data.get("subscription_pool_phone")
|
subscription_pool_phone = state_data.get("subscription_pool_phone")
|
||||||
subscription_pool_bank = state_data.get("subscription_pool_bank")
|
subscription_pool_bank = state_data.get("subscription_pool_bank")
|
||||||
if not all((subscription_user_id, subscription_name)):
|
if not all((subscription_user_id, subscription_name)):
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await callback_query.answer(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=callback_query.message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
async with users_repository.transaction():
|
async with users_repository.transaction():
|
||||||
@@ -843,9 +991,9 @@ async def confirm_add_subscription_callback_handler(
|
|||||||
user_id=subscription_user_id,
|
user_id=subscription_user_id,
|
||||||
)
|
)
|
||||||
if subscription_user is None:
|
if subscription_user is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await callback_query.answer(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=callback_query.message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
subscription_pool = None
|
subscription_pool = None
|
||||||
@@ -855,9 +1003,9 @@ async def confirm_add_subscription_callback_handler(
|
|||||||
pool_id=subscription_pool_id,
|
pool_id=subscription_pool_id,
|
||||||
)
|
)
|
||||||
if subscription_pool is None:
|
if subscription_pool is None:
|
||||||
await message.reply(text=constants.ERROR_MESSAGE)
|
await callback_query.answer(text=constants.ERROR_MESSAGE)
|
||||||
await logic.ask_add_subscription_user(message=message)
|
await logic.ask_new_subscription_user(message=callback_query.message)
|
||||||
await state.set_state(AddSubscriptionState.WAITING_FOR_PHONE)
|
await state.set_state(NewSubscriptionState.WAITING_FOR_PHONE)
|
||||||
return
|
return
|
||||||
|
|
||||||
if subscription_pool is None and all((subscription_pool_phone, subscription_pool_bank)):
|
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 import types
|
||||||
from aiogram.enums import ParseMode
|
from aiogram.enums import ParseMode
|
||||||
from aiogram.fsm.context import FSMContext
|
|
||||||
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
|
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
|
||||||
from pydantic_filters import PagePagination
|
from pydantic_filters import PagePagination
|
||||||
|
|
||||||
from birthday_pool_bot.dto import User
|
from birthday_pool_bot.dto import BankEnum, User
|
||||||
from birthday_pool_bot.repositories.repositories import UsersRepository
|
from birthday_pool_bot.repositories.repositories import (
|
||||||
|
PoolsRepository,
|
||||||
|
SubscriptionsRepository,
|
||||||
|
UsersRepository,
|
||||||
|
)
|
||||||
from . import constants
|
from . import constants
|
||||||
from .callback_data import (
|
from .callback_data import (
|
||||||
AddSubscriptionCallbackData,
|
|
||||||
AddSubscriptionConfirmCallbackData,
|
|
||||||
ConfirmAnswerEnum,
|
ConfirmAnswerEnum,
|
||||||
MenuCallbackData,
|
MenuCallbackData,
|
||||||
|
NewSubscriptionCallbackData,
|
||||||
|
NewSubscriptionConfirmCallbackData,
|
||||||
|
PoolActionEnum,
|
||||||
|
PoolCallbackData,
|
||||||
|
PoolsCallbackData,
|
||||||
|
PoolsBackCallbackData,
|
||||||
SubscriptionActionEnum,
|
SubscriptionActionEnum,
|
||||||
SubscriptionCallbackData,
|
SubscriptionCallbackData,
|
||||||
SubscriptionsCallbackData,
|
SubscriptionsCallbackData,
|
||||||
@@ -200,12 +209,12 @@ async def show_subscriptions(
|
|||||||
text = "Мои подписки:" if subscriptions else "Нет подписок"
|
text = "Мои подписки:" if subscriptions else "Нет подписок"
|
||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
keyboard.button(
|
keyboard.row(types.InlineKeyboardButton(
|
||||||
text=subscription.name,
|
text=subscription.name,
|
||||||
callback_data=SubscriptionCallbackData(
|
callback_data=SubscriptionCallbackData(
|
||||||
to_user_id=subscription.to_user_id,
|
to_user_id=subscription.to_user_id,
|
||||||
).pack(),
|
).pack(),
|
||||||
)
|
))
|
||||||
navigation_row = []
|
navigation_row = []
|
||||||
if page > 1:
|
if page > 1:
|
||||||
navigation_row.append(types.InlineKeyboardButton(
|
navigation_row.append(types.InlineKeyboardButton(
|
||||||
@@ -226,7 +235,7 @@ async def show_subscriptions(
|
|||||||
keyboard.row(
|
keyboard.row(
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="Добавить",
|
text="Добавить",
|
||||||
callback_data=AddSubscriptionCallbackData().pack(),
|
callback_data=NewSubscriptionCallbackData().pack(),
|
||||||
),
|
),
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="Назад",
|
text="Назад",
|
||||||
@@ -273,7 +282,12 @@ async def show_subscription(
|
|||||||
)
|
)
|
||||||
if subscription.pool is not None:
|
if subscription.pool is not None:
|
||||||
if subscription.pool.owner_id == from_user_id:
|
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:
|
else:
|
||||||
text += "Вы участвуете в сборе денег\n\n"
|
text += "Вы участвуете в сборе денег\n\n"
|
||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
@@ -333,7 +347,7 @@ async def delete_subscription(
|
|||||||
await callback_query.answer(text="Подписка успешно удалена")
|
await callback_query.answer(text="Подписка успешно удалена")
|
||||||
|
|
||||||
|
|
||||||
async def ask_add_subscription_user(
|
async def ask_new_subscription_user(
|
||||||
callback_query: types.CallbackQuery | None = None,
|
callback_query: types.CallbackQuery | None = None,
|
||||||
message: types.Message | 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,
|
message: types.Message,
|
||||||
):
|
):
|
||||||
text = (
|
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,
|
message: types.Message,
|
||||||
users_repository: UsersRepository,
|
users_repository: UsersRepository,
|
||||||
subscription_user_id: uuid.UUID,
|
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,
|
message: types.Message,
|
||||||
pools_repository: PoolsRepository,
|
pools_repository: PoolsRepository,
|
||||||
users_repository: UsersRepository,
|
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,
|
user: User,
|
||||||
|
users_repository: UsersRepository,
|
||||||
pools_repository: PoolsRepository,
|
pools_repository: PoolsRepository,
|
||||||
|
subscription_user_id: uuid.UUID,
|
||||||
message: types.Message | None = None,
|
message: types.Message | None = None,
|
||||||
callback_query: types.CallbackQuery | 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)
|
callback_data = SubscriptionsCallbackData.unpack(callback_query.data)
|
||||||
page = callback_data.page
|
page = callback_data.page
|
||||||
|
|
||||||
async with subscriptions_repository.transaction():
|
async with pools_repository.transaction():
|
||||||
total = await subscriptions_repository.get_user_subscriptions_count(user_id=user.id)
|
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))
|
pages_count = total // per_page + int(bool(total % per_page))
|
||||||
subscriptions = [
|
pools = [
|
||||||
subscription
|
pool
|
||||||
async for subscription in subscriptions_repository.get_user_subscriptions(
|
async for pool in pools_repository.get_pools_by_birthday_user_id(
|
||||||
user_id=user.id,
|
birthday_user_id=subscription_user_id,
|
||||||
pagination=PagePagination(page=page, per_page=per_page),
|
pagination=PagePagination(page=page, per_page=per_page),
|
||||||
|
with_owner=True,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
text = "Сборы:" if subscriptions else "Нет сборов"
|
text = "Сборы:" if pools else "Нет сборов"
|
||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
for subscription in subscriptions:
|
for pool in pools:
|
||||||
keyboard.button(
|
keyboard.row(types.InlineKeyboardButton(
|
||||||
text=subscription.name,
|
text=pool.owner.name or "Аноним",
|
||||||
callback_data=SubscriptionCallbackData(
|
callback_data=PoolCallbackData(
|
||||||
to_user_id=subscription.to_user_id,
|
id=pool.id,
|
||||||
).pack(),
|
).pack(),
|
||||||
)
|
))
|
||||||
navigation_row = []
|
navigation_row = []
|
||||||
if page > 1:
|
if page > 1:
|
||||||
navigation_row.append(types.InlineKeyboardButton(
|
navigation_row.append(types.InlineKeyboardButton(
|
||||||
text="<",
|
text="<",
|
||||||
callback_data=SubscriptionsCallbackData(page=page - 1).pack(),
|
callback_data=PoolsCallbackData(page=page - 1).pack(),
|
||||||
))
|
))
|
||||||
if pages_count > 1:
|
if pages_count > 1:
|
||||||
navigation_row.append(types.InlineKeyboardButton(
|
navigation_row.append(types.InlineKeyboardButton(
|
||||||
@@ -504,17 +523,13 @@ async def show_add_subscription_pools(
|
|||||||
if page < pages_count:
|
if page < pages_count:
|
||||||
navigation_row.append(types.InlineKeyboardButton(
|
navigation_row.append(types.InlineKeyboardButton(
|
||||||
text=">",
|
text=">",
|
||||||
callback_data=SubscriptionsCallbackData(page=page + 1).pack(),
|
callback_data=PoolsCallbackData(page=page + 1).pack(),
|
||||||
))
|
))
|
||||||
keyboard.row(*navigation_row)
|
keyboard.row(*navigation_row)
|
||||||
keyboard.row(
|
keyboard.row(
|
||||||
types.InlineKeyboardButton(
|
|
||||||
text="Добавить",
|
|
||||||
callback_data=AddSubscriptionCallbackData().pack(),
|
|
||||||
),
|
|
||||||
types.InlineKeyboardButton(
|
types.InlineKeyboardButton(
|
||||||
text="Назад",
|
text="Назад",
|
||||||
callback_data=MenuCallbackData().pack(),
|
callback_data=PoolsBackCallbackData().pack(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
reply_markup = keyboard.as_markup()
|
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,
|
message: types.Message,
|
||||||
):
|
):
|
||||||
keyboard = ReplyKeyboardBuilder()
|
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,
|
message: types.Message,
|
||||||
user: User,
|
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,
|
message: types.Message,
|
||||||
):
|
):
|
||||||
text = "Выберите банк для приёма платежей"
|
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,
|
message: types.Message,
|
||||||
users_repository: UsersRepository,
|
users_repository: UsersRepository,
|
||||||
pools_repository: PoolsRepository,
|
pools_repository: PoolsRepository,
|
||||||
@@ -663,13 +741,13 @@ async def ask_add_subscription_confirmation(
|
|||||||
keyboard = InlineKeyboardBuilder()
|
keyboard = InlineKeyboardBuilder()
|
||||||
keyboard.button(
|
keyboard.button(
|
||||||
text="Да",
|
text="Да",
|
||||||
callback_data=AddSubscriptionConfirmCallbackData(
|
callback_data=NewSubscriptionConfirmCallbackData(
|
||||||
answer=ConfirmAnswerEnum.YES,
|
answer=ConfirmAnswerEnum.YES,
|
||||||
).pack(),
|
).pack(),
|
||||||
)
|
)
|
||||||
keyboard.button(
|
keyboard.button(
|
||||||
text="Нет",
|
text="Нет",
|
||||||
callback_data=AddSubscriptionConfirmCallbackData(
|
callback_data=NewSubscriptionConfirmCallbackData(
|
||||||
answer=ConfirmAnswerEnum.NO,
|
answer=ConfirmAnswerEnum.NO,
|
||||||
).pack(),
|
).pack(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,15 +24,16 @@ class SetProfileGiftPaymentDataState(StatesGroup):
|
|||||||
WAITING_FOR_BANK = State()
|
WAITING_FOR_BANK = State()
|
||||||
|
|
||||||
|
|
||||||
class AddSubscriptionState(StatesGroup):
|
class NewSubscriptionState(StatesGroup):
|
||||||
WAITING_FOR_PHONE = State()
|
WAITING_FOR_PHONE = State()
|
||||||
WAITING_FOR_DATE = State()
|
WAITING_FOR_DATE = State()
|
||||||
WAITING_FOR_NAME = State()
|
WAITING_FOR_NAME = State()
|
||||||
WAITING_FOR_POOL_DECISION = State()
|
WAITING_FOR_POOL_DECISION = State()
|
||||||
|
WAITING_FOR_CHOOSE_POOL = State()
|
||||||
WAITING_FOR_CONFIRMATION = State()
|
WAITING_FOR_CONFIRMATION = State()
|
||||||
|
|
||||||
|
|
||||||
class AddSubscriptionPoolState(StatesGroup):
|
class NewSubscriptionPoolState(StatesGroup):
|
||||||
WAITING_FOR_DESCRIPTION = State()
|
WAITING_FOR_DESCRIPTION = State()
|
||||||
WAITING_FOR_PAYMENT_PHONE = State()
|
WAITING_FOR_PAYMENT_PHONE = State()
|
||||||
WAITING_FOR_PAYMENT_BANK = State()
|
WAITING_FOR_PAYMENT_BANK = State()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from aiogram import types
|
|||||||
from aiogram.types import User as TelegramUser
|
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:
|
def parse_date(message: types.Message) -> datetime.date:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from typing import Any
|
|||||||
import aiogram
|
import aiogram
|
||||||
import fastapi
|
import fastapi
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
import yarl
|
||||||
|
|
||||||
from birthday_pool_bot.telegram_bot.base import BaseTelegramBotService
|
from birthday_pool_bot.telegram_bot.base import BaseTelegramBotService
|
||||||
|
|
||||||
@@ -14,9 +15,10 @@ class UvicornServer(uvicorn.Server):
|
|||||||
|
|
||||||
class TelegramBotWebhookService(BaseTelegramBotService):
|
class TelegramBotWebhookService(BaseTelegramBotService):
|
||||||
async def listen_events(self):
|
async def listen_events(self):
|
||||||
|
webhook_url = yarl.URL(str(self._settings.root_url)) / self._settings.root_path.lstrip("/")
|
||||||
await self._bot.set_webhook(
|
await self._bot.set_webhook(
|
||||||
url=self._settings.url,
|
url=str(webhook_url),
|
||||||
secret_token=self._settings.secret_token,
|
secret_token=self._settings.secret_access_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.get_server().serve()
|
await self.get_server().serve()
|
||||||
@@ -26,10 +28,9 @@ class TelegramBotWebhookService(BaseTelegramBotService):
|
|||||||
root_url=self._settings.root_url,
|
root_url=self._settings.root_url,
|
||||||
root_path=self._settings.root_path,
|
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._settings.port)
|
||||||
|
|
||||||
config = uvicorn.Config(app=app, host="0.0.0.0", port=self._port)
|
|
||||||
return UvicornServer(config)
|
return UvicornServer(config)
|
||||||
|
|
||||||
async def handler(
|
async def handler(
|
||||||
@@ -37,7 +38,7 @@ class TelegramBotWebhookService(BaseTelegramBotService):
|
|||||||
update: dict[str, Any],
|
update: dict[str, Any],
|
||||||
x_telegram_bot_api_secret_token: str | None = fastapi.Header(None),
|
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(
|
raise fastapi.HTTPException(
|
||||||
status_code=fastapi.status.HTTP_403_FORBIDDEN,
|
status_code=fastapi.status.HTTP_403_FORBIDDEN,
|
||||||
detail="Forbidden.",
|
detail="Forbidden.",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from birthday_pool_bot.telegram_bot.settings import TelegramBotSettings
|
|||||||
|
|
||||||
|
|
||||||
class TelegramBotWebhookSettings(TelegramBotSettings):
|
class TelegramBotWebhookSettings(TelegramBotSettings):
|
||||||
method: Literal[TelegramBotMethodEnum.WEBHOOK.value] = TelegramBotMethodEnum.WEBHOOK
|
method: Literal[TelegramBotMethodEnum.WEBHOOK.value] = TelegramBotMethodEnum.WEBHOOK.value
|
||||||
|
|
||||||
root_url: AnyHttpUrl
|
root_url: AnyHttpUrl
|
||||||
root_path: str = "/"
|
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",
|
"aiogram>=3.23.0",
|
||||||
"uvicorn>=0.38.0",
|
"uvicorn>=0.38.0",
|
||||||
"fastapi>=0.124.4",
|
"fastapi>=0.124.4",
|
||||||
|
"yarl>=1.22.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
sqlite = [
|
sqlite = [
|
||||||
"aiosqlite>=0.21.0",
|
"aiosqlite>=0.21.0",
|
||||||
]
|
]
|
||||||
|
postgresql = [
|
||||||
|
"asyncpg>=0.31.0",
|
||||||
|
]
|
||||||
|
dev = [
|
||||||
|
"ruff>=0.14.11",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
package = false
|
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" },
|
{ 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]]
|
[[package]]
|
||||||
name = "attrs"
|
name = "attrs"
|
||||||
version = "25.4.0"
|
version = "25.4.0"
|
||||||
@@ -196,9 +228,11 @@ name = "birthday-pool-bot"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "aiogram" },
|
||||||
{ name = "alembic" },
|
{ name = "alembic" },
|
||||||
{ name = "apscheduler" },
|
{ name = "apscheduler" },
|
||||||
{ name = "facet" },
|
{ name = "facet" },
|
||||||
|
{ name = "fastapi" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "pydantic-extra-types", extra = ["phonenumbers"] },
|
{ name = "pydantic-extra-types", extra = ["phonenumbers"] },
|
||||||
{ name = "pydantic-filters" },
|
{ name = "pydantic-filters" },
|
||||||
@@ -207,23 +241,28 @@ dependencies = [
|
|||||||
{ name = "sqlalchemy" },
|
{ name = "sqlalchemy" },
|
||||||
{ name = "sqlmodel" },
|
{ name = "sqlmodel" },
|
||||||
{ name = "typer" },
|
{ name = "typer" },
|
||||||
|
{ name = "uvicorn" },
|
||||||
|
{ name = "yarl" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "ruff" },
|
||||||
|
]
|
||||||
|
postgresql = [
|
||||||
|
{ name = "asyncpg" },
|
||||||
|
]
|
||||||
sqlite = [
|
sqlite = [
|
||||||
{ name = "aiosqlite" },
|
{ name = "aiosqlite" },
|
||||||
]
|
]
|
||||||
telegram = [
|
|
||||||
{ name = "aiogram" },
|
|
||||||
{ name = "fastapi" },
|
|
||||||
{ name = "uvicorn" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
|
{ name = "aiogram", specifier = ">=3.23.0" },
|
||||||
{ name = "alembic", specifier = ">=1.17.2" },
|
{ name = "alembic", specifier = ">=1.17.2" },
|
||||||
{ name = "apscheduler", specifier = ">=3.11.2" },
|
{ name = "apscheduler", specifier = ">=3.11.2" },
|
||||||
{ name = "facet", specifier = ">=0.10.1" },
|
{ name = "facet", specifier = ">=0.10.1" },
|
||||||
|
{ name = "fastapi", specifier = ">=0.124.4" },
|
||||||
{ name = "pydantic", specifier = ">=2.12.5" },
|
{ name = "pydantic", specifier = ">=2.12.5" },
|
||||||
{ name = "pydantic-extra-types", extras = ["phonenumbers"], specifier = ">=2.10.6" },
|
{ name = "pydantic-extra-types", extras = ["phonenumbers"], specifier = ">=2.10.6" },
|
||||||
{ name = "pydantic-filters", git = "https://github.com/OlegYurchik/pydantic-filters?rev=2ca8b822d59feaf5f19f36b570974d314ba5e330" },
|
{ 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 = "sqlalchemy", specifier = ">=2.0.44" },
|
||||||
{ name = "sqlmodel", specifier = ">=0.0.27" },
|
{ name = "sqlmodel", specifier = ">=0.0.27" },
|
||||||
{ name = "typer", specifier = ">=0.20.0" },
|
{ name = "typer", specifier = ">=0.20.0" },
|
||||||
|
{ name = "uvicorn", specifier = ">=0.38.0" },
|
||||||
|
{ name = "yarl", specifier = ">=1.22.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[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" }]
|
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]]
|
[[package]]
|
||||||
name = "certifi"
|
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" },
|
{ 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]]
|
[[package]]
|
||||||
name = "shellingham"
|
name = "shellingham"
|
||||||
version = "1.5.4"
|
version = "1.5.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user