Add AD lookup by email → CARD_ID → SQL tabel check for ds.krivochenko@sibcem.ru
This commit is contained in:
+148
-107
@@ -1,7 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Проверка подключения к SQL Server и загрузки данных табеля
|
Проверка подключения к SQL Server и загрузки данных табеля
|
||||||
за последние 5 месяцев.
|
за последние 5 месяцев для конкретного сотрудника.
|
||||||
|
|
||||||
|
Поиск сотрудника:
|
||||||
|
1. Ищем в AD по email (ds.krivochenko@sibcem.ru) → получаем extensionAttribute2 = CARD_ID
|
||||||
|
2. По CARD_ID ищем в SQL (UOV_SELFSERVICE_PR_EMP) → получаем EMP_ID
|
||||||
|
3. По EMP_ID загружаем табель (UOV_SELFSERVICE_TB_TABEL) за 5 месяцев
|
||||||
|
|
||||||
Запуск:
|
Запуск:
|
||||||
cd /opt/trueconf_bot
|
cd /opt/trueconf_bot
|
||||||
@@ -35,6 +40,7 @@ load_env(ENV_PATH)
|
|||||||
# Карта соответствия: Имя переменной в боте -> Название карточки в сейфе
|
# Карта соответствия: Имя переменной в боте -> Название карточки в сейфе
|
||||||
CREDENTIALS_MAP = {
|
CREDENTIALS_MAP = {
|
||||||
"DB_PASSWORD": os.getenv("PW_ID_SQL", "").strip(' "\'\r\n'),
|
"DB_PASSWORD": os.getenv("PW_ID_SQL", "").strip(' "\'\r\n'),
|
||||||
|
"AD_PASSWORD": os.getenv("PW_ID_AD", "").strip(' "\'\r\n'),
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -42,78 +48,57 @@ CREDENTIALS_MAP = {
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
DB_USER = ""
|
DB_USER = ""
|
||||||
DB_PASSWORD = ""
|
DB_PASSWORD = ""
|
||||||
|
AD_USER = ""
|
||||||
|
AD_PASSWORD = ""
|
||||||
|
|
||||||
# Пытаемся найти passwork в нескольких местах
|
for pw_path in ["/opt/passwork", os.path.join(BASE_DIR, "passwork"), os.path.join(BASE_DIR, "config", "passwork")]:
|
||||||
passwork_paths = [
|
|
||||||
"/opt/passwork",
|
|
||||||
os.path.join(BASE_DIR, "passwork"),
|
|
||||||
os.path.join(BASE_DIR, "config", "passwork"),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Добавляем /opt/trueconf_bot в путь, если мы в контейнере
|
|
||||||
if BASE_DIR.startswith("/"):
|
|
||||||
passwork_paths.append("/passwork")
|
|
||||||
|
|
||||||
print("🔍 Ищем модуль passwork в путях:")
|
|
||||||
for pw_path in passwork_paths:
|
|
||||||
exists = "✅" if os.path.isdir(pw_path) else "❌"
|
|
||||||
print(f" {exists} {pw_path}")
|
|
||||||
|
|
||||||
# Добавляем все существующие пути
|
|
||||||
for pw_path in passwork_paths:
|
|
||||||
if os.path.isdir(pw_path) and pw_path not in sys.path:
|
if os.path.isdir(pw_path) and pw_path not in sys.path:
|
||||||
sys.path.insert(0, pw_path)
|
sys.path.insert(0, pw_path)
|
||||||
print(f" → Добавлен в sys.path: {pw_path}")
|
|
||||||
|
|
||||||
# Также добавляем корень проекта
|
|
||||||
if BASE_DIR not in sys.path:
|
if BASE_DIR not in sys.path:
|
||||||
sys.path.insert(0, BASE_DIR)
|
sys.path.insert(0, BASE_DIR)
|
||||||
|
|
||||||
passwork_loaded = False
|
|
||||||
try:
|
try:
|
||||||
from passwork import get_passwork_secrets
|
from passwork import get_passwork_secrets
|
||||||
print("\n✅ Модуль passwork найден!")
|
print("🔐 Загрузка секретов из Passwork...")
|
||||||
|
|
||||||
required_cards = [name for name in CREDENTIALS_MAP.values() if name]
|
required_cards = [name for name in CREDENTIALS_MAP.values() if name]
|
||||||
print(f" Запрашиваем карточки: {required_cards}")
|
|
||||||
|
|
||||||
passwork_pool = get_passwork_secrets(required_cards=required_cards)
|
passwork_pool = get_passwork_secrets(required_cards=required_cards)
|
||||||
print(f" Получено карточек: {len(passwork_pool)}")
|
|
||||||
|
|
||||||
for var_name, card_name in CREDENTIALS_MAP.items():
|
for var_name, card_name in CREDENTIALS_MAP.items():
|
||||||
if not card_name:
|
if not card_name:
|
||||||
continue
|
continue
|
||||||
clean_card = card_name.strip(' "\'\r\n')
|
clean_card = card_name.strip(' "\'\r\n')
|
||||||
card_data = passwork_pool.get(clean_card)
|
card_data = passwork_pool.get(clean_card)
|
||||||
if card_data is None:
|
if card_data is None:
|
||||||
print(f" ⚠️ Карточка '{clean_card}' не найдена в ответе")
|
print(f" ⚠️ Карточка '{clean_card}' не найдена")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
globals()[var_name] = card_data["password"].strip(' "\'\r\n')
|
globals()[var_name] = card_data["password"].strip(' "\'\r\n')
|
||||||
if var_name == "DB_PASSWORD":
|
if var_name == "AD_PASSWORD":
|
||||||
|
globals()["AD_USER"] = card_data.get("login", "").strip(' "\'\r\n')
|
||||||
|
elif var_name == "DB_PASSWORD":
|
||||||
globals()["DB_USER"] = card_data.get("login", "").strip(' "\'\r\n')
|
globals()["DB_USER"] = card_data.get("login", "").strip(' "\'\r\n')
|
||||||
print(f" ✓ {var_name} загружен из карточки '{clean_card}'")
|
print(f" ✓ {var_name} из карточки '{clean_card}'")
|
||||||
|
except ImportError:
|
||||||
passwork_loaded = True
|
print("⚠️ Модуль passwork не найден")
|
||||||
|
|
||||||
except ImportError as e:
|
|
||||||
print(f"\n❌ Модуль passwork не импортируется: {e}")
|
|
||||||
print(" Варианты: модуль не установлен, нет прав, неверный путь")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\n⚠️ Ошибка Passwork: {e}")
|
print(f"⚠️ Ошибка Passwork: {e}")
|
||||||
|
|
||||||
# Фоллбэк: проверяем системные переменные окружения
|
# Фоллбэк на переменные окружения
|
||||||
if not DB_PASSWORD:
|
if not DB_PASSWORD:
|
||||||
DB_PASSWORD = os.getenv("DB_PASSWORD", "").strip()
|
DB_PASSWORD = os.getenv("DB_PASSWORD", "").strip()
|
||||||
DB_USER = os.getenv("DB_USER", DB_USER).strip()
|
DB_USER = os.getenv("DB_USER", DB_USER).strip()
|
||||||
if DB_PASSWORD:
|
if not AD_PASSWORD:
|
||||||
print(" ✓ DB_PASSWORD из переменной окружения")
|
AD_PASSWORD = os.getenv("AD_PASSWORD", "").strip()
|
||||||
|
AD_USER = os.getenv("AD_USER", AD_USER).strip()
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 3. Настройки подключения
|
# 3. Настройки подключения
|
||||||
# ============================================================
|
# ============================================================
|
||||||
DB_SERVER = os.getenv("SQL_SERVER", "SRVKEM-MOBILEIN.sibcem.ru")
|
DB_SERVER = os.getenv("SQL_SERVER", "SRVKEM-MOBILEIN.sibcem.ru")
|
||||||
DB_NAME = os.getenv("SQL_DB_NAME", "BossCopy")
|
DB_NAME = os.getenv("SQL_DB_NAME", "BossCopy")
|
||||||
|
AD_SERVER = os.getenv("AD_SERVER", "ldap://172.16.20.20")
|
||||||
|
AD_BASES = (
|
||||||
|
"OU=-Пользователи,DC=sibcem,DC=ru",
|
||||||
|
"OU=Планшеты,OU=enabled,OU=БезКомпьютеров,DC=sibcem,DC=ru",
|
||||||
|
)
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
@@ -133,7 +118,6 @@ try:
|
|||||||
print(f"✅ pymssql загружен (версия {pymssql.__version__})")
|
print(f"✅ pymssql загружен (версия {pymssql.__version__})")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print("❌ pymssql не установлен!")
|
print("❌ pymssql не установлен!")
|
||||||
print(" pip install pymssql")
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -155,60 +139,143 @@ except Exception as e:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 6. Проверка доступности таблиц
|
# 6. Поиск сотрудника в AD по email → CARD_ID
|
||||||
# ============================================================
|
# ============================================================
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(" Проверка доступности таблиц")
|
print(" Поиск сотрудника в Active Directory")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
tables_to_check = [
|
# Email для поиска
|
||||||
("UOV_SELFSERVICE_PR_EMP", "Таблица сотрудников"),
|
TARGET_EMAIL = "ds.krivochenko@sibcem.ru"
|
||||||
("UOV_SELFSERVICE_TB_TABEL", "Табель учёта рабочего времени"),
|
print(f" Ищем: {TARGET_EMAIL}")
|
||||||
]
|
|
||||||
|
|
||||||
for table, desc in tables_to_check:
|
# Импортируем ldap3 и ищем
|
||||||
try:
|
try:
|
||||||
cursor.execute(f"SELECT TOP 1 * FROM {table}")
|
from ldap3 import Server, Connection, ALL
|
||||||
row = cursor.fetchone()
|
from ldap3.utils.conv import escape_filter_chars
|
||||||
if row:
|
|
||||||
cols = [col[0] for col in cursor.description]
|
server = Server(AD_SERVER, get_info=ALL)
|
||||||
print(f"✅ {desc}")
|
ldap_conn = Connection(server, user=AD_USER, password=AD_PASSWORD, auto_bind=True)
|
||||||
print(f" Таблица: {table}")
|
|
||||||
print(f" Столбцы: {', '.join(cols[:8])}")
|
# Строим фильтр как в ad_search.py
|
||||||
if len(cols) > 8:
|
short_username = TARGET_EMAIL.split("@")[0] if "@" in TARGET_EMAIL else TARGET_EMAIL
|
||||||
print(f" ... ещё {len(cols) - 8} столбцов")
|
|
||||||
else:
|
or_parts = [
|
||||||
print(f"⚠️ {desc} — таблица пуста")
|
"(mail={})".format(TARGET_EMAIL),
|
||||||
|
"(userPrincipalName={})".format(TARGET_EMAIL),
|
||||||
|
"(userPrincipalName={})".format(short_username + "@sibcem.ru"),
|
||||||
|
"(sAMAccountName={})".format(short_username),
|
||||||
|
]
|
||||||
|
or_filter = "(|{})".format("".join(or_parts))
|
||||||
|
search_filter = "(&{}{})".format("(objectClass=user)", or_filter)
|
||||||
|
|
||||||
|
print(f" LDAP-фильтр: {search_filter}")
|
||||||
|
|
||||||
|
card_id_from_ad = None
|
||||||
|
ldap_entry = None
|
||||||
|
|
||||||
|
for base in AD_BASES:
|
||||||
|
ldap_conn.search(
|
||||||
|
search_base=base,
|
||||||
|
search_filter=search_filter,
|
||||||
|
attributes=["cn", "sAMAccountName", "mail", "userPrincipalName", "extensionAttribute2"],
|
||||||
|
)
|
||||||
|
if ldap_conn.entries:
|
||||||
|
ldap_entry = ldap_conn.entries[0]
|
||||||
|
print(f" ✅ Найден в OU: {base}")
|
||||||
|
print(f" CN : {ldap_entry.cn}")
|
||||||
|
print(f" sAMAccountName: {ldap_entry.sAMAccountName}")
|
||||||
|
print(f" mail : {ldap_entry.mail}")
|
||||||
|
ext2 = str(ldap_entry.extensionAttribute2) if hasattr(ldap_entry, 'extensionAttribute2') and ldap_entry.extensionAttribute2 else "(не задан)"
|
||||||
|
print(f" extensionAttribute2: {ext2}")
|
||||||
|
card_id_from_ad = ext2
|
||||||
|
break
|
||||||
|
|
||||||
|
if not ldap_entry:
|
||||||
|
print(f" ❌ Сотрудник не найден в AD по email {TARGET_EMAIL}")
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
print("❌ ldap3 не установлен")
|
||||||
|
sys.exit(1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ {desc} — ошибка: {e}")
|
print(f"❌ Ошибка LDAP: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 7. Загрузка табеля за последние 5 месяцев
|
# 7. Поиск EMP_ID по CARD_ID в SQL
|
||||||
|
# ============================================================
|
||||||
|
print()
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Поиск сотрудника в SQL Server")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
emp_id = None
|
||||||
|
card_id = None
|
||||||
|
|
||||||
|
if card_id_from_ad:
|
||||||
|
card_id = card_id_from_ad
|
||||||
|
print(f" CARD_ID из AD: {card_id}")
|
||||||
|
cursor.execute("SELECT e.ID, e.CARD_ID FROM UOV_SELFSERVICE_PR_EMP e WHERE e.CARD_ID = %s", (card_id,))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
emp_id = row[0]
|
||||||
|
print(f" ✅ Найден: emp_id={emp_id}, CARD_ID={row[1]}")
|
||||||
|
else:
|
||||||
|
print(f" ⚠️ Сотрудник с CARD_ID={card_id} не найден в UOV_SELFSERVICE_PR_EMP")
|
||||||
|
|
||||||
|
# Если не нашли по CARD_ID из AD — пробуем по email через SQL
|
||||||
|
if not emp_id:
|
||||||
|
print(f" ⚠️ Пробуем поиск по email через SQL...")
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT e.ID, e.CARD_ID, e.EMAIL FROM UOV_SELFSERVICE_PR_EMP e WHERE e.EMAIL LIKE %s OR e.EMAIL LIKE %s ORDER BY e.ID LIMIT 1",
|
||||||
|
(f"%{TARGET_EMAIL}%", f"%{short_username}@%")
|
||||||
|
)
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
emp_id = row[0]
|
||||||
|
card_id = row[1]
|
||||||
|
print(f" ✅ Найден: emp_id={emp_id}, CARD_ID={card_id}")
|
||||||
|
else:
|
||||||
|
print(f" ❌ Сотрудник не найден")
|
||||||
|
|
||||||
|
# Если нашли — выводим инфу
|
||||||
|
if emp_id:
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT f.SNAME, d.NAME, appoint.NAME, e.EMAIL "
|
||||||
|
"FROM UOV_SELFSERVICE_PR_EMP e "
|
||||||
|
"JOIN UOV_SELFSERVICE_PR_TRANS t ON t.EMP_ID = e.ID "
|
||||||
|
"JOIN UOV_SELFSERVICE_HR_FIRM f ON f.ID = e.FIRM_ID "
|
||||||
|
"JOIN UOV_SELFSERVICE_HR_DEPT d ON d.ID = t.DEPT_ID "
|
||||||
|
"JOIN UOV_SELFSERVICE_ST_APPOINT appoint ON appoint.ID = t.APPOINT_ID "
|
||||||
|
"WHERE e.CARD_ID = %s AND t.D_FROM <= CAST(GETDATE() AS DATE) "
|
||||||
|
"AND (t.D_TO >= CAST(GETDATE() AS DATE) OR t.D_TO = CAST('1999-12-31' AS DATE))",
|
||||||
|
(card_id,)
|
||||||
|
)
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
print(f"\n 📋 Информация о сотруднике:")
|
||||||
|
print(f" Компания : {row[0]}")
|
||||||
|
print(f" Отдел : {row[1]}")
|
||||||
|
print(f" Должность: {row[2]}")
|
||||||
|
print(f" Email : {row[3]}")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 8. Загрузка табеля за последние 5 месяцев
|
||||||
# ============================================================
|
# ============================================================
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(" Загрузка табеля за последние 5 месяцев")
|
print(" Загрузка табеля за последние 5 месяцев")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
|
if not emp_id:
|
||||||
|
print(" ❌ Не удалось найти сотрудника — завершение")
|
||||||
|
conn.close()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
months_back = 5
|
months_back = 5
|
||||||
|
|
||||||
try:
|
|
||||||
cursor.execute("SELECT TOP 1 e.ID, e.CARD_ID FROM UOV_SELFSERVICE_PR_EMP e ORDER BY e.ID")
|
|
||||||
emp_row = cursor.fetchone()
|
|
||||||
if not emp_row:
|
|
||||||
print("❌ Нет сотрудников в таблице UOV_SELFSERVICE_PR_EMP")
|
|
||||||
conn.close()
|
|
||||||
sys.exit(1)
|
|
||||||
test_emp_id = emp_row[0]
|
|
||||||
test_card_id = emp_row[1]
|
|
||||||
print(f"Тестовый сотрудник: emp_id={test_emp_id}, card_id={test_card_id}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Ошибка: {e}")
|
|
||||||
conn.close()
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
for i in range(months_back):
|
for i in range(months_back):
|
||||||
month = now.month - i
|
month = now.month - i
|
||||||
year = now.year
|
year = now.year
|
||||||
@@ -227,7 +294,7 @@ for i in range(months_back):
|
|||||||
ORDER BY e.D ASC
|
ORDER BY e.D ASC
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
cursor.execute(query, (test_emp_id, year, month))
|
cursor.execute(query, (emp_id, year, month))
|
||||||
records = cursor.fetchall()
|
records = cursor.fetchall()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ❌ Ошибка запроса: {e}")
|
print(f" ❌ Ошибка запроса: {e}")
|
||||||
@@ -260,34 +327,8 @@ for i in range(months_back):
|
|||||||
print(f" {d} | {str(r[1]).strip():>3} | {float(r[2]) if r[2] else 0:.1f} ч.")
|
print(f" {d} | {str(r[1]).strip():>3} | {float(r[2]) if r[2] else 0:.1f} ч.")
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 8. Тест с конкретным CARD_ID
|
# Закрытие
|
||||||
# ============================================================
|
# ============================================================
|
||||||
print()
|
|
||||||
print("=" * 60)
|
|
||||||
print(" Тест с конкретным CARD_ID")
|
|
||||||
print("=" * 60)
|
|
||||||
|
|
||||||
test_card_id = input("Введите CARD_ID (или Enter для теста с первым): ").strip()
|
|
||||||
if test_card_id:
|
|
||||||
print(f" Поиск сотрудника с CARD_ID={test_card_id}...")
|
|
||||||
cursor.execute("SELECT e.ID FROM UOV_SELFSERVICE_PR_EMP e WHERE e.CARD_ID = %s", (test_card_id,))
|
|
||||||
row = cursor.fetchone()
|
|
||||||
if not row:
|
|
||||||
print(f" ⚠️ Сотрудник с CARD_ID={test_card_id} не найден")
|
|
||||||
else:
|
|
||||||
emp_id = row[0]
|
|
||||||
print(f" ✅ Найден: emp_id={emp_id}")
|
|
||||||
for i in range(min(3, months_back)):
|
|
||||||
month = now.month - i
|
|
||||||
year = now.year
|
|
||||||
while month <= 0:
|
|
||||||
month += 12
|
|
||||||
year -= 1
|
|
||||||
month_name = calendar.month_name[month]
|
|
||||||
cursor.execute(query, (emp_id, year, month))
|
|
||||||
records = cursor.fetchall()
|
|
||||||
print(f" {month_name} {year}: {len(records)} записей")
|
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|||||||
Reference in New Issue
Block a user