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

This commit is contained in:
2026-07-23 20:47:02 +07:00
parent 54b019f3b9
commit 51b632ec7d
+52 -10
View File
@@ -2,6 +2,8 @@ import logging
import asyncio import asyncio
import os import os
import sys import sys
import json
import httpx
from trueconf import Router, Message from trueconf import Router, Message
from trueconf.types import FSInputFile 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.states import get_state, set_state, clear_state
from utils.stats_logger import log_menu_stats from utils.stats_logger import log_menu_stats
from service_desk.handlers import create_ticket_in_sd
# Безопасный импорт конфигурации # Безопасный импорт конфигурации
try: try:
@@ -96,12 +97,47 @@ def get_ad_user_info(user_id: str) -> dict | None:
return 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: async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
""" """
Создать заявку в Service Desk для запроса доступа к Trueconf. Создать заявку в Service Desk для запроса доступа к Trueconf.
Полностью автономная функция.
Если пользователь не найден в AD или у него нет email — создаёт заявку от DEFAULT_REQUESTER (ai@sibcem.ru).
Если пользователь найден — создаёт заявку от его email.
""" """
subject = "Запрос доступа к Trueconf" 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}") logger.info(f"AD search result for SD ticket ({user_id}): {ad_info}")
if ad_info and ad_info.get("mail"): if ad_info and ad_info.get("mail"):
# Пользователь найден в AD и имеет email
requester_email = ad_info["mail"] requester_email = ad_info["mail"]
city = ad_info.get("city", "Кемерово") city = ad_info.get("city", "Кемерово")
description = ( description = (
@@ -118,7 +153,6 @@ async def create_sd_ticket_for_trueconf(user_id: str, cn: str) -> str | None:
f"но не имеет группы 2FA. Требуется выдача доступа." f"но не имеет группы 2FA. Требуется выдача доступа."
) )
else: else:
# Пользователь не найден в AD ИЛИ не имеет email — создаём от DEFAULT_REQUESTER (ai@sibcem.ru)
requester_email = DEFAULT_REQUESTER requester_email = DEFAULT_REQUESTER
city = "Кемерово" city = "Кемерово"
logger.info(f"Using DEFAULT_REQUESTER ({requester_email}) for user {user_id} (cn={cn})") 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: try:
logger.info(f"Calling create_ticket_in_sd: requester={requester_email}, city={city}") logger.info(f"Calling SD API directly: requester={requester_email}, city={city}")
ticket_id = await create_ticket_in_sd(requester_email, subject, description, city) ticket_id = await _send_sd_api_request(requester_email, subject, description, city)
if ticket_id: if ticket_id:
logger.info(f"SD ticket created for {cn}: #{ticket_id} (requester={requester_email})") logger.info(f"SD ticket created for {cn}: #{ticket_id} (requester={requester_email})")
else: else:
@@ -192,8 +226,16 @@ async def instruct_router_handler(msg: Message):
if cn is None: if cn is None:
cn = user_id # fallback cn = user_id # fallback
# Создаём заявку в SD # Проверяем наличие группы 2FA в AD перед созданием заявки
ticket_id = await create_sd_ticket_for_trueconf(user_id, cn) 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) text = INSTRUCT_TRUECONF_WITH_AD(EMOJI_DIGITS, cn, ticket_id)