149 lines
5.1 KiB
Python
149 lines
5.1 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from app.models.models import (
|
|
BotNotification, BotNotificationSubscription, BotUser,
|
|
)
|
|
from app.settings_cache import SettingsCache
|
|
|
|
try:
|
|
from app.models.models import User
|
|
except ImportError:
|
|
User = None
|
|
|
|
|
|
async def _get_max_user_id_by_role(db: AsyncSession, role: str) -> int | None:
|
|
if User is None:
|
|
return None
|
|
result = await db.execute(
|
|
select(User.max_user_id).where(
|
|
User.role == role, User.is_active == True,
|
|
User.max_user_id.isnot(None)
|
|
).limit(1)
|
|
)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
async def _get_user_max_ids_by_role(db: AsyncSession, role: str) -> list[int]:
|
|
if User is None:
|
|
return []
|
|
result = await db.execute(
|
|
select(User.max_user_id).where(
|
|
User.role == role, User.is_active == True,
|
|
User.max_user_id.isnot(None)
|
|
)
|
|
)
|
|
return [row[0] for row in result.fetchall() if row[0]]
|
|
|
|
|
|
async def _log_notification(db: AsyncSession, ntype: str, recipient_type: str,
|
|
recipient_max_user_id: int | None, title: str, body: str,
|
|
related_type: str = "", related_id: int | None = None):
|
|
n = BotNotification(
|
|
type=ntype, recipient_type=recipient_type,
|
|
recipient_max_user_id=recipient_max_user_id,
|
|
title=title, body=body,
|
|
related_type=related_type, related_id=related_id
|
|
)
|
|
db.add(n)
|
|
await db.flush()
|
|
return n
|
|
|
|
|
|
async def notify_operator(db: AsyncSession, max_api, text: str, title: str = "",
|
|
related_type: str = "", related_id: int | None = None):
|
|
max_ids = await _get_user_max_ids_by_role(db, "owner")
|
|
sent_count = 0
|
|
for mid in max_ids:
|
|
try:
|
|
await max_api.send_message(user_id=mid, text=text, format="markdown")
|
|
sent_count += 1
|
|
except Exception:
|
|
pass
|
|
await _log_notification(
|
|
db, "operator_alert", "operator", max_ids[0] if max_ids else None,
|
|
title or "Уведомление оператору", text,
|
|
related_type, related_id
|
|
)
|
|
return sent_count
|
|
|
|
|
|
async def notify_level2(db: AsyncSession, max_api, text: str, title: str = "",
|
|
related_type: str = "", related_id: int | None = None):
|
|
max_ids = await _get_user_max_ids_by_role(db, "engineer")
|
|
sent_count = 0
|
|
for mid in max_ids:
|
|
try:
|
|
await max_api.send_message(user_id=mid, text=text, format="markdown")
|
|
sent_count += 1
|
|
except Exception:
|
|
pass
|
|
await _log_notification(
|
|
db, "level2_alert", "level2", max_ids[0] if max_ids else None,
|
|
title or "Уведомление инженеру", text,
|
|
related_type, related_id
|
|
)
|
|
return sent_count
|
|
|
|
|
|
async def notify_client_status_change(db: AsyncSession, max_api,
|
|
bot_user: BotUser, conv_id: int,
|
|
new_status: str):
|
|
text = f"Статус вашего обращения №{conv_id} изменён на «{new_status}»."
|
|
try:
|
|
await max_api.send_message(user_id=bot_user.max_user_id, text=text, format="markdown")
|
|
except Exception:
|
|
pass
|
|
await _log_notification(
|
|
db, "status_change", "client", bot_user.max_user_id,
|
|
"Статус обращения", text, "conversation", conv_id
|
|
)
|
|
|
|
|
|
async def notify_ticket_created(db: AsyncSession, ticket, max_api):
|
|
ticket_text = (
|
|
f"🆕 **Новый тикет {ticket.ticket_number}**\n"
|
|
f"Приоритет: {ticket.priority}\n"
|
|
f"Описание: {ticket.description[:200]}\n"
|
|
f"Обращение №{ticket.id}"
|
|
)
|
|
await notify_level2(
|
|
db, max_api, ticket_text,
|
|
title=f"Тикет {ticket.ticket_number}",
|
|
related_type="ticket", related_id=ticket.id
|
|
)
|
|
|
|
|
|
async def notify_handoff_escalation(db: AsyncSession, max_api,
|
|
bot_user: BotUser, conv_id: int,
|
|
text: str = ""):
|
|
msg = (
|
|
f"🔴 **Эскалация оператору**\n"
|
|
f"Пользователь: {bot_user.first_name or '—'} (ID {bot_user.max_user_id})\n"
|
|
f"Обращение №{conv_id}\n"
|
|
f"Текст: {text[:200] if text else '—'}"
|
|
)
|
|
await notify_operator(
|
|
db, max_api, msg,
|
|
title="Эскалация",
|
|
related_type="conversation", related_id=conv_id
|
|
)
|
|
|
|
|
|
async def get_subscribed_users(db: AsyncSession, notify_type: str = "broadcast") -> list[BotUser]:
|
|
col_map = {
|
|
"broadcast": BotNotificationSubscription.notify_on_broadcast,
|
|
"status_change": BotNotificationSubscription.notify_on_status_change,
|
|
"reply": BotNotificationSubscription.notify_on_reply,
|
|
}
|
|
col = col_map.get(notify_type)
|
|
if col is None:
|
|
return []
|
|
result = await db.execute(
|
|
select(BotUser).join(
|
|
BotNotificationSubscription,
|
|
BotNotificationSubscription.user_id == BotUser.id
|
|
).where(col == True)
|
|
)
|
|
return list(result.scalars().all())
|