201 lines
6.7 KiB
Python
201 lines
6.7 KiB
Python
"""
|
||
Обработчики авторизации:
|
||
- bot_started — первый запуск / перезапуск
|
||
- /start команда
|
||
- Шаринг контакта
|
||
"""
|
||
import re
|
||
|
||
from maxapi.dispatcher import Router
|
||
from maxapi.filters import F
|
||
from maxapi.filters.contact import ContactFilter
|
||
from maxapi.types.attachments.attachment import ContactAttachmentPayload
|
||
from maxapi.types.attachments.contact import Contact as ContactAttachment
|
||
from maxapi.types.updates.bot_started import BotStarted
|
||
from maxapi.types.updates.message_created import MessageCreated
|
||
from maxapi.context import BaseContext
|
||
from maxapi.filters.command import Command
|
||
|
||
from bot.keyboards import contact_request_kb, main_menu_kb
|
||
from bot.states import AuthStates
|
||
from database.queries.bot_users import (
|
||
authorize_bot_user,
|
||
block_bot_user,
|
||
get_bot_user_by_max_id,
|
||
upsert_bot_user,
|
||
)
|
||
from database.queries.org_users import find_by_phone
|
||
from database.queries.message_log import log_message
|
||
|
||
router = Router(router_id="start")
|
||
|
||
|
||
def normalize_phone(raw: str) -> str:
|
||
"""Убираем всё кроме цифр, заменяем ведущую 8 → 7."""
|
||
digits = re.sub(r"\D", "", raw)
|
||
if digits.startswith("8") and len(digits) == 11:
|
||
digits = "7" + digits[1:]
|
||
return digits
|
||
|
||
|
||
@router.bot_started()
|
||
async def on_bot_started(event: BotStarted, context: BaseContext) -> None:
|
||
user = event.user
|
||
bot_user = await upsert_bot_user(
|
||
max_user_id=user.user_id,
|
||
max_chat_id=event.chat_id,
|
||
username=getattr(user, "username", None),
|
||
first_name=getattr(user, "name", None),
|
||
)
|
||
|
||
if bot_user["is_blocked"]:
|
||
await event.bot.send_message(
|
||
chat_id=event.chat_id,
|
||
text=(
|
||
"⛔ Ваш номер не найден в системе. Доступ заблокирован.\n"
|
||
"Обратитесь к администратору для подключения."
|
||
),
|
||
)
|
||
return
|
||
|
||
if bot_user["is_authorized"]:
|
||
await context.set_state(None)
|
||
await event.bot.send_message(
|
||
chat_id=event.chat_id,
|
||
text="👋 С возвращением! Выберите действие:",
|
||
attachments=[main_menu_kb()],
|
||
)
|
||
return
|
||
|
||
# Новый пользователь — запрашиваем контакт
|
||
await context.set_state(AuthStates.waiting_contact)
|
||
await event.bot.send_message(
|
||
chat_id=event.chat_id,
|
||
text=(
|
||
"👋 Добро пожаловать в систему технической поддержки!\n\n"
|
||
"Для входа нажмите кнопку ниже и поделитесь своим номером телефона."
|
||
),
|
||
attachments=[contact_request_kb()],
|
||
)
|
||
|
||
|
||
@router.message_created(Command("start"))
|
||
async def on_start_command(event: MessageCreated, context: BaseContext) -> None:
|
||
chat_id, user_id = event.get_ids()
|
||
if user_id is None or chat_id is None:
|
||
return
|
||
|
||
bot_user = await get_bot_user_by_max_id(user_id)
|
||
if bot_user is None:
|
||
# Первый раз — как bot_started
|
||
await upsert_bot_user(
|
||
max_user_id=user_id,
|
||
max_chat_id=chat_id,
|
||
username=None,
|
||
first_name=None,
|
||
)
|
||
await context.set_state(AuthStates.waiting_contact)
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text=(
|
||
"👋 Добро пожаловать!\n\n"
|
||
"Поделитесь номером телефона для доступа к системе."
|
||
),
|
||
attachments=[contact_request_kb()],
|
||
)
|
||
return
|
||
|
||
if bot_user["is_blocked"]:
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text="⛔ Доступ заблокирован. Обратитесь к администратору.",
|
||
)
|
||
return
|
||
|
||
if not bot_user["is_authorized"]:
|
||
await context.set_state(AuthStates.waiting_contact)
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text="Поделитесь номером телефона для доступа:",
|
||
attachments=[contact_request_kb()],
|
||
)
|
||
return
|
||
|
||
await context.set_state(None)
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text="Главное меню:",
|
||
attachments=[main_menu_kb()],
|
||
)
|
||
|
||
|
||
@router.message_created(ContactFilter(), states=AuthStates.waiting_contact)
|
||
async def on_contact_shared(
|
||
event: MessageCreated,
|
||
contact: ContactAttachment,
|
||
context: BaseContext,
|
||
) -> None:
|
||
chat_id, user_id = event.get_ids()
|
||
if user_id is None or chat_id is None:
|
||
return
|
||
|
||
# Извлекаем телефон из VCF
|
||
payload = contact.payload
|
||
if not isinstance(payload, ContactAttachmentPayload):
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text="Не удалось прочитать контакт. Попробуйте ещё раз.",
|
||
attachments=[contact_request_kb()],
|
||
)
|
||
return
|
||
|
||
vcf = payload.vcf
|
||
raw_phone = vcf.phone
|
||
if not raw_phone:
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text="В контакте не найден номер телефона. Попробуйте ещё раз.",
|
||
attachments=[contact_request_kb()],
|
||
)
|
||
return
|
||
|
||
phone = normalize_phone(raw_phone)
|
||
display_name = vcf.full_name
|
||
|
||
# Логируем входящий контакт
|
||
await log_message(
|
||
direction="in",
|
||
max_user_id=user_id,
|
||
max_chat_id=chat_id,
|
||
message_id=None,
|
||
text=f"[Контакт: {raw_phone}]",
|
||
)
|
||
|
||
# Ищем в белом списке
|
||
org_user = await find_by_phone(phone)
|
||
if org_user is None:
|
||
await block_bot_user(max_user_id=user_id, phone=phone)
|
||
await context.set_state(None)
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text=(
|
||
"⛔ Ваш номер не найден в системе.\n"
|
||
"Доступ заблокирован. Обратитесь к администратору для подключения."
|
||
),
|
||
)
|
||
return
|
||
|
||
# Авторизуем
|
||
await authorize_bot_user(
|
||
max_user_id=user_id,
|
||
phone=phone,
|
||
org_id=org_user["org_id"],
|
||
first_name=display_name,
|
||
)
|
||
await context.set_state(None)
|
||
|
||
await event.bot.send_message(
|
||
chat_id=chat_id,
|
||
text="✅ Вы успешно авторизованы! Выберите действие:",
|
||
attachments=[main_menu_kb()],
|
||
)
|