Files
site_aegisone/max_bot/app/handlers/consent.py
T
angel 72b6879f4b v1.7.0: refactor max_bot to flat structure, add VCF+UserModel+NLP history context, portal pages and proxy fixes
- Refactored max_bot from nested packages to flat module structure
- Q2: Extended BotUser model (patronymic, email, org, address, vcf_raw, contact_hash, phone_verified, email_verified, last_interaction, total_conversations, total_tickets)
- Q2: VCF parser (FN, N, TEL, EMAIL, ORG, ADR), upsert on re-contact, NLP history context (_get_user_history_context -> YandexGPT)
- Q1: Broadcast preview modal with 10s confirmation timer
- Q3: CSS var(--white)->var(--bg-card), var(--text)->var(--text-primary)
- Q4: bot_settings showNotification(), editable max_bot_id
- Q5: Webhook secret passthrough via X-Max-Bot-Api-Secret
- Masking sensitive keys, dialog_cleared handler, migrate via _add_column_if_not_exists()
- Rate limit (asyncio.sleep 0.5 per 10), dead code removed, conv.intent context in contact.py
- Portal pages: bot_consent, bot_kb (edit), bot_settings, bot_test, bot_tickets, portal_settings
- Tests: 21/21 passing, added test_yandex_gpt.py, test_email_sender.py
- Deploy: deploy_full.sh, schema.sql, seed_knowledge_base.sql
2026-05-29 02:30:30 +03:00

108 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime
import logging
from sqlalchemy import select
from app.database import async_session
from app.models import BotUser, BotConversation, BotMessage
from app.max_api import max_api
from app.config_reader import config_reader
from app.keyboards import contact_keyboard, consent_keyboard, return_to_consent_keyboard
logger = logging.getLogger(__name__)
async def handle_consent_callback(user_id: int, conv_id: int, callback_id: str) -> None:
if callback_id == "consent_yes":
await handle_consent_yes(user_id, conv_id)
elif callback_id == "consent_no":
await handle_consent_no(user_id, conv_id)
async def handle_consent_response(user_id: int, conv_id: int, text: str) -> None:
text_lower = text.strip().lower()
consent_words = ["да", "даю", "согласен", "согласна", "yes", "ok", "хорошо", "даю согласие"]
refuse_words = ["нет", "не даю", "отказ", "no", "не согласен", "не согласна"]
if any(w in text_lower for w in consent_words):
await handle_consent_yes(user_id, conv_id)
elif any(w in text_lower for w in refuse_words):
await handle_consent_no(user_id, conv_id)
else:
await max_api.send_message(
user_id,
"Пожалуйста, дайте чёткий ответ — даёте ли вы согласие на обработку "
"персональных данных? Это необходимо для обработки вашего запроса.",
attachments=consent_keyboard(),
)
async def handle_consent_yes(user_id: int, conv_id: int) -> None:
async with async_session() as db:
result = await db.execute(select(BotUser).where(BotUser.id == user_id))
user = result.scalar_one_or_none()
if user:
user.consent_given = True
user.consent_date = datetime.datetime.utcnow()
result = await db.execute(
select(BotConversation).where(BotConversation.id == conv_id)
)
conv = result.scalar_one_or_none()
if conv:
conv.state = "awaiting_contact"
await db.commit()
await max_api.send_message(
user_id,
"Спасибо! Поделитесь, пожалуйста, вашим контактом, чтобы мы могли "
"связаться с вами.\n\n"
"Нажмите кнопку «Поделиться контактом» или введите номер телефона / email вручную.",
attachments=contact_keyboard(),
)
async def handle_consent_no(user_id: int, conv_id: int) -> None:
async with async_session() as db:
result = await db.execute(
select(BotConversation).where(BotConversation.id == conv_id)
)
conv = result.scalar_one_or_none()
if conv:
conv.state = "consent_refused"
await db.commit()
phones = config_reader.get_phones()
email = config_reader.get_site_mail()
phone_text = "\n".join(
f"📞 {phone}" for phone, _ in phones
)
await max_api.send_message(
user_id,
f"Без вашего согласия мы не можем обработать обращение.\n\n"
f"Вы можете позвонить нам:\n{phone_text}\n\n"
f"Или написать на почту: {email}\n\n"
f"Если передумаете и захотите дать согласие — просто напишите об этом.",
)
async def handle_refused_again(user_id: int, conv_id: int, text: str) -> None:
text_lower = text.strip().lower()
consent_words = ["да", "даю", "согласен", "согласна", "yes", "ok", "хорошо", "даю согласие", "передумал", "согласен дать"]
if any(w in text_lower for w in consent_words):
await handle_consent_yes(user_id, conv_id)
else:
phones = config_reader.get_phones()
email = config_reader.get_site_mail()
phone_text = ", ".join(phone for phone, _ in phones)
await max_api.send_message(
user_id,
f"Связаться с нами можно только по телефону {phone_text} "
f"или по почте {email}. "
f"Если хотите дать согласие на обработку данных — напишите «Даю согласие».",
attachments=return_to_consent_keyboard(),
)