Обновить instruct/handlers.py
This commit is contained in:
+51
-9
@@ -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 перед созданием заявки
|
||||||
|
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)
|
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user