28 Commits

Author SHA1 Message Date
dddennnisss b269e7d6ec fix: CSV QUOTE_ALL for proper column separation with commas in values 2026-07-27 12:30:25 +07:00
dddennnisss 23d073f9d8 fix: replace newlines in descriptions for proper CSV table format 2026-07-27 12:27:54 +07:00
dddennnisss 9c80ff716e fix: CSV encoding utf-8-sig for proper Cyrillic display in Excel 2026-07-27 12:24:01 +07:00
dddennnisss 00630cd18c feat: add JSON and CSV file output with argparse 2026-07-27 12:20:49 +07:00
dddennnisss 748b262936 fix: get API_KEY directly from passwork, remove unused config import 2026-07-27 11:57:13 +07:00
dddennnisss f03cd70b48 fix: get API_KEY directly from passwork on srvkem-ii-02 2026-07-27 11:54:17 +07:00
dddennnisss 16b0b9f063 fix: safe config import with getattr + env fallback 2026-07-27 11:49:01 +07:00
dddennnisss 23a18b7396 fix: add fallback for SERVER_URL and API_KEY, add logging 2026-07-27 11:47:58 +07:00
dddennnisss 08220a6858 fix: add fallback for SERVER_URL if config import fails 2026-07-27 11:47:28 +07:00
dddennnisss 6c8c79cf70 fix: config path for /opt/GigaAM/sd/ (parent dir in sys.path) 2026-07-27 11:38:55 +07:00
dddennnisss a1d391cf5f feat: fetch tickets from SD using requests + config (SERVER_URL, API_KEY from passwork) 2026-07-27 11:29:17 +07:00
dddennnisss b7b099cb38 feat: use SERVER_URL and API_KEY from config (passwork), remove LOCAL_SD 2026-07-27 10:42:43 +07:00
dddennnisss 6494ed1e17 feat: fetch tickets from LOCAL_SD config using from config import * 2026-07-27 00:32:25 +07:00
dddennnisss 46cbcde05b feat: fetch tickets from LOCAL_SD config using from config import * 2026-07-27 00:29:19 +07:00
dddennnisss a980bea083 feat: fetch tickets from LOCAL_SD config using from config import * 2026-07-27 00:28:23 +07:00
dddennnisss f974f678f8 feat: fetch tickets from LOCAL_SD config using from config import * 2026-07-27 00:27:14 +07:00
dddennnisss 3dff2c2a95 feat: fetch tickets from LOCAL_SD config using from config import * 2026-07-27 00:26:13 +07:00
dddennnisss 167e79fa2c feat: fetch tickets from LOCAL_SD config 2026-07-27 00:24:58 +07:00
dddennnisss 8aa13afad9 feat: fetch tickets from LOCAL_SD config 2026-07-27 00:23:49 +07:00
dddennnisss 08f6b67971 feat: add LOCAL_SD config, fetch tickets with group/desc/assignee/category 2026-07-27 00:23:14 +07:00
dddennnisss 42335ce015 refactor: use requests sync, graceful config import 2026-07-27 00:14:39 +07:00
dddennnisss 13f99579f5 revert: remove LOCAL_SD from config.py 2026-07-26 23:35:33 +07:00
dddennnisss 3396e3e65b revert: remove LOCAL_SD from config.py 2026-07-26 23:35:09 +07:00
dddennnisss a48b484ea1 feat: read SD config from config.py, add category/assignee, support date arg 2026-07-26 23:20:32 +07:00
dddennnisss 1ee2b6387a fix: get category and assignee from ticket detail API 2026-07-26 23:13:20 +07:00
dddennnisss d14930aa39 feat: add fetch_tickets.py with group, description, assignee, category 2026-07-26 23:10:57 +07:00
dddennnisss 4ad93cfdd5 revert cf1d526304
revert Clean main branch
2026-07-14 17:01:24 +07:00
dddennnisss cf1d526304 Clean main branch 2026-07-14 09:46:58 +00:00
2 changed files with 169 additions and 0 deletions
+1
View File
@@ -115,6 +115,7 @@ ENABLE_FUZZY_CORRECTION = True # Нечёткое исправление по
SERVER_URL = "https://servicedesk.sibcem.ru:8080"
ENDPOINT = f"{SERVER_URL}/api/v3/requests"
# Системный email-адрес учетной записи ИИ-сортировщика в Service Desk
DEFAULT_REQUESTER = "ai@sibcem.ru"
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env python3
"""Получение списка заявок из ServiceDesk Plus. Экспорт: Группа, Описание, Назначено, Категория в JSONL/JSON/CSV."""
import requests
import json
import csv
import urllib3
from datetime import datetime
from html import unescape
import re
import sys
import os
# Отключаем ворнинги для чистой работы консоли
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# --- ПОЛУЧЕНИЕ API_KEY ИЗ PASSWORK ---
SERVER_URL = "https://servicedesk.sibcem.ru:8080"
API_KEY = ""
# 1. Пробуем passwork напрямую
try:
sys.path.insert(0, "/opt/passwork")
from passwork import get_passwork_secrets
passwork_pool = get_passwork_secrets(required_cards=["sdesktoken"])
card = passwork_pool.get("sdesktoken")
if card:
API_KEY = card.get("password", "").strip()
print("LOG: API_KEY получен из passwork (sdesktoken)")
else:
print("LOG: Карточка sdesktoken не найдена в passwork", file=sys.stderr)
except Exception as e:
print(f"LOG: Passwork ошибка: {e}", file=sys.stderr)
# 2. Пробуем config.py
if not API_KEY:
try:
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import config as cfg
API_KEY = getattr(cfg, 'API_KEY', "")
if API_KEY:
print("LOG: API_KEY получен из config.py")
except Exception:
pass
# 3. Пробуем env var
if not API_KEY:
API_KEY = os.environ.get("SD_API_KEY", "")
if API_KEY:
print("LOG: API_KEY получен из SD_API_KEY")
if not API_KEY:
print("LOG: ОШИБКА: API_KEY не найден нигде! Нужен passwork или SD_API_KEY", file=sys.stderr)
sys.exit(1)
print(f"LOG: Подключение к {SERVER_URL}")
def get_ts(req):
ct = req.get("created_time", {})
if isinstance(ct, dict):
v = ct.get("value", "0")
return int(v) if v else 0
return 0
def clean_html(text):
if not text:
return ""
text = re.sub(r'<[^>]+>', '', text)
text = unescape(text)
return text.strip()
def get_name(obj):
if not obj:
return ""
if isinstance(obj, dict):
return obj.get("name", "") or obj.get("display_value", "")
return str(obj)
def get_ticket_detail(ticket_id):
try:
url = f"{SERVER_URL}/api/v3/requests/{ticket_id}"
headers = {"authtoken": API_KEY, "Accept": "application/vnd.manageengine.sdp.v3+json"}
resp = requests.get(url, headers=headers, verify=False, timeout=15.0)
resp.raise_for_status()
data = resp.json()
return data.get("request", data)
except Exception as e:
return {}
def list_tickets(from_date="2026-07-20", json_file=None, csv_file=None):
url = f"{SERVER_URL}/api/v3/requests"
headers = {"authtoken": API_KEY, "Accept": "application/vnd.manageengine.sdp.v3+json"}
date_obj = datetime.strptime(from_date, "%Y-%m-%d")
from_date_ms = int(date_obj.replace(tzinfo=__import__('datetime').timezone.utc).timestamp() * 1000)
print(f"LOG: Загрузка заявок с {from_date}...")
resp = requests.get(url, headers=headers, verify=False, timeout=30.0)
resp.raise_for_status()
data = resp.json()
all_reqs = data.get("requests", [])
from_date_reqs = [r for r in all_reqs if get_ts(r) >= from_date_ms]
print(f"LOG: Найдено заявок с {from_date}: {len(from_date_reqs)}")
rows = []
for i, req in enumerate(from_date_reqs):
if (i + 1) % 10 == 0:
print(f" Обработано {i + 1}/{len(from_date_reqs)}...")
req_id = req.get("request_id", req.get("id", "?"))
detail = get_ticket_detail(req_id)
group = req.get("group", {})
group_name = get_name(group)
desc = detail.get("description", "")
desc_clean = clean_html(desc).replace('\n', ' ').replace('\r', ' ')
tech = detail.get("technician", {})
assignee = get_name(tech)
cat = detail.get("category", {})
category = get_name(cat)
rows.append({
"group": group_name,
"description": desc_clean,
"assignee": assignee,
"category": category
})
# Определяем путь для файлов по умолчанию (та же директория что и скрипт)
script_dir = os.path.dirname(os.path.abspath(__file__))
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
if json_file is None:
json_file = os.path.join(script_dir, f"tickets_{timestamp}.json")
if csv_file is None:
csv_file = os.path.join(script_dir, f"tickets_{timestamp}.csv")
# Сохраняем JSON
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(rows, f, ensure_ascii=False, indent=2)
print(f"LOG: JSON сохранён: {json_file}")
# Сохраняем CSV (utf-8-sig для корректного отображения кириллицы в Excel)
with open(csv_file, 'w', encoding='utf-8-sig', newline='') as f:
writer = csv.DictWriter(f, fieldnames=["group", "description", "assignee", "category"], quoting=csv.QUOTE_ALL)
writer.writeheader()
writer.writerows(rows)
print(f"LOG: CSV сохранён: {csv_file}")
# Выводим JSONL в консоль
for row in rows:
print(json.dumps(row, ensure_ascii=False))
print(f"LOG: Выведено {len(rows)} заявок", file=sys.stderr)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Выгрузка заявок из ServiceDesk Plus")
parser.add_argument("--from", dest="from_date", default="2026-07-20", help="Дата начала (YYYY-MM-DD)")
parser.add_argument("--json", dest="json_file", default=None, help="Путь к JSON файлу")
parser.add_argument("--csv", dest="csv_file", default=None, help="Путь к CSV файлу")
args = parser.parse_args()
list_tickets(from_date=args.from_date, json_file=args.json_file, csv_file=args.csv_file)