feat: явно указаны зависимости к Protocol для перехода к имплементации
This commit is contained in:
12
shared/jwt_base.py
Normal file
12
shared/jwt_base.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class JWTConfig(BaseModel):
|
||||
SECRET_KEY: str
|
||||
ALGORITHM: str = 'HS256'
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 # 7 days
|
||||
|
||||
|
||||
class JWTBase:
|
||||
def __init__(self, config: JWTConfig) -> None:
|
||||
self.config = config
|
||||
@@ -4,11 +4,8 @@ import uuid
|
||||
import jwt
|
||||
import pydantic
|
||||
|
||||
|
||||
class JWTConfig(pydantic.BaseModel):
|
||||
SECRET_KEY: str
|
||||
ALGORITHM: str = 'HS256'
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 # 7 days
|
||||
from shared.jwt_base import JWTBase
|
||||
from src.usecase import JWTEncoder
|
||||
|
||||
|
||||
class JWTPayload(pydantic.BaseModel):
|
||||
@@ -17,10 +14,7 @@ class JWTPayload(pydantic.BaseModel):
|
||||
username: str | None
|
||||
|
||||
|
||||
class JWT:
|
||||
def __init__(self, config: JWTConfig) -> None:
|
||||
self.config = config
|
||||
|
||||
class JWT(JWTBase, JWTEncoder):
|
||||
def encode_access_token(
|
||||
self,
|
||||
user_id: uuid.UUID,
|
||||
|
||||
@@ -4,6 +4,8 @@ from typing import Any
|
||||
import httpx
|
||||
from pydantic import BaseModel
|
||||
|
||||
from src.usecase import Parser
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -16,23 +18,12 @@ class FetchChannelResponse(BaseModel):
|
||||
pts: int
|
||||
|
||||
|
||||
class ParserClient:
|
||||
class ParserClient(Parser):
|
||||
def __init__(self, base_url: str, timeout: float = 5.0):
|
||||
self.base_url = base_url.rstrip('/')
|
||||
self.timeout = timeout
|
||||
|
||||
async def fetch_telegram_channel(self, username: str) -> FetchChannelResponse | None:
|
||||
"""
|
||||
Проверяет существование канала в Telegram и получает его метаданные.
|
||||
|
||||
Returns:
|
||||
FetchChannelResponse если канал найден
|
||||
None если канал не найден (404)
|
||||
|
||||
Raises:
|
||||
httpx.HTTPError для других ошибок (таймаут, network error, 5xx)
|
||||
"""
|
||||
# Убираем @ если пользователь его указал
|
||||
username = username.lstrip('@')
|
||||
|
||||
url = f'{self.base_url}/fetch-telegram-channel'
|
||||
|
||||
@@ -8,11 +8,12 @@ from tortoise.transactions import in_transaction
|
||||
|
||||
from shared.datebase_base import DatabaseBase
|
||||
from src import domain
|
||||
from usecase import Database
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Postgres(DatabaseBase):
|
||||
class Postgres(DatabaseBase, Database):
|
||||
def transaction(self) -> typing.AsyncContextManager[None]:
|
||||
return in_transaction()
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ import logging
|
||||
from aiogram.types import BotCommand, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
|
||||
from shared.telegram_base import TelegramBase
|
||||
from usecase import TelegramBotWriter
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TelegramBot(TelegramBase):
|
||||
class TelegramBot(TelegramBase, TelegramBotWriter):
|
||||
async def send_message(self, text: str, chat_id: int) -> None:
|
||||
await self.bot.send_message(chat_id=chat_id, text=text)
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
from shared.config_helper import load_settings
|
||||
from shared.datebase_base import DatabaseConfig
|
||||
from shared.jwt_base import JWTConfig
|
||||
from shared.logger import LoggerConfig
|
||||
from shared.telegram_base import TelegramConfig
|
||||
from src.adapter.jwt import JWTConfig
|
||||
|
||||
|
||||
class AppConfig(BaseModel):
|
||||
|
||||
@@ -17,15 +17,12 @@ async def on_chat_join_request(event: ChatJoinRequest) -> None:
|
||||
log.error('Failed to get user data from chat join request')
|
||||
return
|
||||
|
||||
# Получаем invite_link, по которой пользователь отправил запрос
|
||||
invite_link = event.invite_link
|
||||
if not invite_link or not invite_link.invite_link:
|
||||
log.debug('No invite_link in chat join request event')
|
||||
return
|
||||
|
||||
usecase = deps.get_usecase()
|
||||
|
||||
await usecase.handle_subscription(
|
||||
await deps.get_usecase().handle_subscription(
|
||||
user_telegram_id=event.from_user.id,
|
||||
username=event.from_user.username,
|
||||
invite_link=invite_link.invite_link,
|
||||
|
||||
@@ -30,17 +30,17 @@ async def on_chat_member_updated(event: ChatMemberUpdated) -> None:
|
||||
is_now_not_member = new_status in ('left', 'kicked')
|
||||
user_left = was_member and is_now_not_member
|
||||
|
||||
usecase = deps.get_usecase()
|
||||
|
||||
if user_joined:
|
||||
invite_link = event.invite_link.invite_link if event.invite_link else None
|
||||
if not invite_link:
|
||||
log.debug('No invite_link in chat member update event')
|
||||
return
|
||||
|
||||
await usecase.handle_subscription(
|
||||
await deps.get_usecase().handle_subscription(
|
||||
user_telegram_id=event.from_user.id, username=event.from_user.username, invite_link=invite_link
|
||||
)
|
||||
|
||||
elif user_left:
|
||||
await usecase.handle_unsubscription(user_telegram_id=event.from_user.id, channel_telegram_id=event.chat.id)
|
||||
await deps.get_usecase().handle_unsubscription(
|
||||
user_telegram_id=event.from_user.id, channel_telegram_id=event.chat.id
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@ usecase = Usecase(
|
||||
database=postgres,
|
||||
telegram_bot=telegram,
|
||||
jwt_encoder=jwt_encoder,
|
||||
parser_client=parser_client,
|
||||
parser=parser_client,
|
||||
)
|
||||
deps.set_usecase(usecase)
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ class FetchChannelResponse(typing.Protocol):
|
||||
title: str
|
||||
|
||||
|
||||
class ParserClient(typing.Protocol):
|
||||
class Parser(typing.Protocol):
|
||||
async def fetch_telegram_channel(self, username: str) -> FetchChannelResponse | None: ...
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ class Usecase:
|
||||
database: Database
|
||||
telegram_bot: TelegramBotWriter
|
||||
jwt_encoder: JWTEncoder
|
||||
parser_client: ParserClient
|
||||
parser: Parser
|
||||
|
||||
async def ensure_workspace_access(self, workspace_id: UUID, user_id: UUID) -> domain.Workspace:
|
||||
workspace = await self.database.get_workspace_for_user(workspace_id, user_id)
|
||||
|
||||
@@ -30,7 +30,7 @@ async def attach_channel_to_purchase_plan(
|
||||
channel = await self.database.get_channel(username=input.username)
|
||||
|
||||
if not channel:
|
||||
parser_response = await self.parser_client.fetch_telegram_channel(input.username)
|
||||
parser_response = await self.parser.fetch_telegram_channel(input.username)
|
||||
if not parser_response:
|
||||
raise domain.TelegramChannelNotFound(input.username)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user