Обновить instruct/handlers.py

This commit is contained in:
2026-07-23 20:47:02 +07:00
parent 54b019f3b9
commit 51b632ec7d
+51 -9
View File
@@ -2,6 +2,8 @@ import logging
import asyncio
import os
import sys
import json
import httpx
from trueconf import Router, Message
from trueconf.types import FSInputFile
@@ -16,7 +18,6 @@ from utils.texts import (
)
from utils.states import get_state, set_state, clear_state
from utils.stats_logger import log_menu_stats
from service_desk.handlers import create_ticket_in_sd
# Безопасный импорт конфигурации
try:
@@ -96,12 +97,47 @@ def get_ad_user_info(user_id: str) -> dict | None:
return None
async def _send_sd_api_request(requester_email: str, subject: str, description: str, city: str) -> str | None:
"""
Автономная прямая отправка HTTP-запроса в Service Desk API v3.
"""
# Если запрашивает системный ИИ или не указан email — ищем по ИМЕНИ
if requester_email == DEFAULT_REQUESTER or requester_email == "ai@sibcem.ru":
requester_payload = {"name": "Искусственный Интеллект"}
else:
requester_payload = {"email_id": requester_email}
payload = {
"request": {
"subject": subject,
"description": description,
"requester": requester_payload,
"udf_fields": {
"udf_pick_301": city
}
}
}
url = f"{SD_URL.rstrip('/')}/api/v3/requests"
headers = {"TECHNICIAN_KEY": SD_TOKEN}
data = {"input_data": json.dumps(payload)}
async with httpx.AsyncClient(verify=False) as client:
response = await client.post(url, headers=headers, data=data, timeout=15.0)
if response.status_code in (200, 201):
res_json = response.json()
ticket_id = res_json.get("request", {}).get("id")
return str(ticket_id) if ticket_id else None
else:
logger.error(f"Service Desk API Error ({response.status_code}): {response.text}")
return None
async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
"""
Создать заявку в Service Desk для запроса доступа к Trueconf.
Если пользователь не найден в AD или у него нет email — создаёт заявку от DEFAULT_REQUESTER (ai@sibcem.ru).
Если пользователь найден — создаёт заявку от его email.
Полностью автономная функция.
"""
subject = "Запрос доступа к Trueconf"
@@ -110,7 +146,6 @@ async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
logger.info(f"AD search result for SD ticket ({user_id}): {ad_info}")
if ad_info and ad_info.get("mail"):
# Пользователь найден в AD и имеет email
requester_email = ad_info["mail"]
city = ad_info.get("city", "Кемерово")
description = (
@@ -118,7 +153,6 @@ async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
f"но не имеет группы 2FA. Требуется выдача доступа."
)
else:
# Пользователь не найден в AD ИЛИ не имеет email — создаём от DEFAULT_REQUESTER (ai@sibcem.ru)
requester_email = DEFAULT_REQUESTER
city = "Кемерово"
logger.info(f"Using DEFAULT_REQUESTER ({requester_email}) for user {user_id} (cn={cn})")
@@ -135,8 +169,8 @@ async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
)
try:
logger.info(f"Calling create_ticket_in_sd: requester={requester_email}, city={city}")
ticket_id = await create_ticket_in_sd(requester_email, subject, description, city)
logger.info(f"Calling SD API directly: requester={requester_email}, city={city}")
ticket_id = await _send_sd_api_request(requester_email, subject, description, city)
if ticket_id:
logger.info(f"SD ticket created for {cn}: #{ticket_id} (requester={requester_email})")
else:
@@ -192,8 +226,16 @@ async def instruct_router_handler(msg: Message):
if cn is None:
cn = user_id # fallback
# Создаём заявку в SD
# Проверяем наличие группы 2FA в AD перед созданием заявки
from utils.ad_checker import check_group_membership
ad_check = check_group_membership(cn, "2FA")
ticket_id = None
# Создаём заявку в SD ТОЛЬКО если у пользователя НЕТ группы 2FA (или он не найден)
if not ad_check.get("in_group", False):
ticket_id = await create_sd_ticket_for_trueconf(user_id, cn)
else:
logger.info(f"User {cn} already has 2FA group. SD ticket creation skipped.")
# Показываем текст с результатом
text = INSTRUCT_TRUECONF_WITH_AD(EMOJI_DIGITS, cn, ticket_id)