89 lines
2.6 KiB
Python
89 lines
2.6 KiB
Python
import hashlib
|
|
import re
|
|
|
|
from .database import BotDatabase
|
|
from .domain import Binding
|
|
|
|
TOKEN_PATTERN = re.compile(r"^[A-Za-z0-9_-]{20,100}$")
|
|
|
|
|
|
def hash_token(token: str) -> bytes:
|
|
return hashlib.sha256(token.encode("utf-8")).digest()
|
|
|
|
|
|
class BotBindingRepository:
|
|
"""Доступ бота только к функциям БД схемы binding.
|
|
Обертка над хранимыми функциями БД."""
|
|
|
|
def __init__(self, database: BotDatabase) -> None:
|
|
self.database = database
|
|
|
|
async def consume(
|
|
self,
|
|
token_hash: bytes,
|
|
telegram_user_id: int,
|
|
telegram_chat_id: int
|
|
) -> Binding | None:
|
|
async with self.database.transaction() as connection:
|
|
cursor = await connection.execute(
|
|
"""
|
|
SELECT *
|
|
FROM binding.consume_v1(%s, %s, %s)
|
|
""",
|
|
(token_hash, telegram_user_id, telegram_chat_id)
|
|
)
|
|
row = await cursor.fetchone()
|
|
return self._binding(row) if row else None
|
|
|
|
async def find(
|
|
self,
|
|
telegram_user_id: int,
|
|
member_id: str | None = None,
|
|
) -> Binding | None:
|
|
async with self.database.transaction() as connection:
|
|
cursor = await connection.execute(
|
|
"""
|
|
SELECT *
|
|
FROM binding.find_by_telegram_v1(%s, %s)
|
|
""",
|
|
(telegram_user_id, member_id)
|
|
)
|
|
row = await cursor.fetchone()
|
|
return self._binding(row) if row else None
|
|
|
|
@staticmethod
|
|
def _binding(row: dict) -> Binding:
|
|
return Binding(
|
|
member_id=str(row["member_id"]),
|
|
domain=str(row["domain"]),
|
|
bitrix_user_id=int(row["bitrix_user_id"]),
|
|
telegram_user_id=int(row["telegram_user_id"])
|
|
)
|
|
|
|
|
|
class BindingService:
|
|
"""Служба управления привязками пользователей."""
|
|
|
|
def __init__(
|
|
self,
|
|
repository: BotBindingRepository
|
|
) -> None:
|
|
self.repository = repository
|
|
|
|
async def consume(
|
|
self,
|
|
token: str,
|
|
telegram_user_id: int,
|
|
telegram_chat_id: int
|
|
) -> Binding | None:
|
|
if not TOKEN_PATTERN.fullmatch(token):
|
|
return None
|
|
return await self.repository.consume(
|
|
hash_token(token),
|
|
telegram_user_id,
|
|
telegram_chat_id
|
|
)
|
|
|
|
async def find(self, telegram_user_id: int) -> Binding | None:
|
|
return await self.repository.find(telegram_user_id)
|