Fix: properly load DB credentials from Passwork + .env
This commit is contained in:
+118
-76
@@ -3,27 +3,22 @@
|
|||||||
Проверка подключения к SQL Server и загрузки данных табеля
|
Проверка подключения к SQL Server и загрузки данных табеля
|
||||||
за последние 5 месяцев.
|
за последние 5 месяцев.
|
||||||
|
|
||||||
Запуск внутри Docker-контейнера проекта:
|
Запуск:
|
||||||
docker exec -it trueconf-bot python3 test_tabel_check.py
|
|
||||||
|
|
||||||
ИЛИ напрямую на production (если есть доступ к серверу):
|
|
||||||
cd /opt/trueconf_bot
|
cd /opt/trueconf_bot
|
||||||
python3 test_tabel_check.py
|
python3 test_tabel_check.py
|
||||||
|
|
||||||
Требования: pymssql, passwork (опционально)
|
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import calendar
|
import calendar
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 1. Загрузка .env из /opt/trueconf_bot/config/.env
|
# 1. Загрузка .env
|
||||||
# ============================================================
|
# ============================================================
|
||||||
ENV_PATH = "/opt/trueconf_bot/config/.env"
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
ENV_PATH = os.path.join(BASE_DIR, "config", ".env")
|
||||||
|
|
||||||
def load_env(filepath):
|
def load_env(filepath):
|
||||||
"""Загружает переменные из .env файла."""
|
|
||||||
try:
|
try:
|
||||||
with open(filepath, "r", encoding="utf-8") as f:
|
with open(filepath, "r", encoding="utf-8") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
@@ -33,30 +28,94 @@ def load_env(filepath):
|
|||||||
key, value = line.split("=", 1)
|
key, value = line.split("=", 1)
|
||||||
os.environ[key.strip()] = value.strip(' "\'\r\n')
|
os.environ[key.strip()] = value.strip(' "\'\r\n')
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"⚠️ Файл {filepath} не найден. Используются системные переменные.")
|
print(f"⚠️ Файл {filepath} не найден.")
|
||||||
|
|
||||||
load_env(ENV_PATH)
|
load_env(ENV_PATH)
|
||||||
|
|
||||||
|
# Карта соответствия: Имя переменной в боте -> Название карточки в сейфе
|
||||||
|
CREDENTIALS_MAP = {
|
||||||
|
"DB_PASSWORD": os.getenv("PW_ID_SQL", "").strip(' "\'\r\n'),
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 2. Попытка загрузки из Passwork (как в оригинальном config.py)
|
# 2. Загрузка паролей из Passwork
|
||||||
|
# ============================================================
|
||||||
|
DB_USER = ""
|
||||||
|
DB_PASSWORD = ""
|
||||||
|
|
||||||
|
# Пытаемся найти 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:
|
||||||
|
sys.path.insert(0, pw_path)
|
||||||
|
print(f" → Добавлен в sys.path: {pw_path}")
|
||||||
|
|
||||||
|
# Также добавляем корень проекта
|
||||||
|
if BASE_DIR not in sys.path:
|
||||||
|
sys.path.insert(0, BASE_DIR)
|
||||||
|
|
||||||
|
passwork_loaded = False
|
||||||
|
try:
|
||||||
|
from passwork import get_passwork_secrets
|
||||||
|
print("\n✅ Модуль passwork найден!")
|
||||||
|
|
||||||
|
required_cards = [name for name in CREDENTIALS_MAP.values() if name]
|
||||||
|
print(f" Запрашиваем карточки: {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():
|
||||||
|
if not card_name:
|
||||||
|
continue
|
||||||
|
clean_card = card_name.strip(' "\'\r\n')
|
||||||
|
card_data = passwork_pool.get(clean_card)
|
||||||
|
if card_data is None:
|
||||||
|
print(f" ⚠️ Карточка '{clean_card}' не найдена в ответе")
|
||||||
|
continue
|
||||||
|
|
||||||
|
globals()[var_name] = card_data["password"].strip(' "\'\r\n')
|
||||||
|
if var_name == "DB_PASSWORD":
|
||||||
|
globals()["DB_USER"] = card_data.get("login", "").strip(' "\'\r\n')
|
||||||
|
print(f" ✓ {var_name} загружен из карточки '{clean_card}'")
|
||||||
|
|
||||||
|
passwork_loaded = True
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"\n❌ Модуль passwork не импортируется: {e}")
|
||||||
|
print(" Варианты: модуль не установлен, нет прав, неверный путь")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n⚠️ Ошибка Passwork: {e}")
|
||||||
|
|
||||||
|
# Фоллбэк: проверяем системные переменные окружения
|
||||||
|
if not DB_PASSWORD:
|
||||||
|
DB_PASSWORD = os.getenv("DB_PASSWORD", "").strip()
|
||||||
|
DB_USER = os.getenv("DB_USER", DB_USER).strip()
|
||||||
|
if DB_PASSWORD:
|
||||||
|
print(" ✓ DB_PASSWORD из переменной окружения")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 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")
|
||||||
DB_USER = os.getenv("DB_USER", "")
|
|
||||||
DB_PASSWORD = os.getenv("DB_PASSWORD", "")
|
|
||||||
|
|
||||||
# Если Passwork не загружен, пробуем .db.env
|
print()
|
||||||
if not DB_PASSWORD:
|
|
||||||
db_env_path = "/opt/trueconf_bot/config/.db.env"
|
|
||||||
if os.path.exists(db_env_path):
|
|
||||||
print(f"📂 Попытка загрузки DB-пароля из {db_env_path}...")
|
|
||||||
load_env(db_env_path)
|
|
||||||
DB_USER = os.getenv("DB_USER", DB_USER)
|
|
||||||
DB_PASSWORD = os.getenv("DB_PASSWORD", DB_PASSWORD)
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# 3. Подключение к SQL Server
|
|
||||||
# ============================================================
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(" Проверка подключения к SQL Server")
|
print(" Проверка подключения к SQL Server")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
@@ -66,6 +125,9 @@ print(f" Логин : {DB_USER}")
|
|||||||
print(f" Пароль : {'*' * len(DB_PASSWORD) if DB_PASSWORD else '(не задан)'}")
|
print(f" Пароль : {'*' * len(DB_PASSWORD) if DB_PASSWORD else '(не задан)'}")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 4. Проверка pymssql
|
||||||
|
# ============================================================
|
||||||
try:
|
try:
|
||||||
import pymssql
|
import pymssql
|
||||||
print(f"✅ pymssql загружен (версия {pymssql.__version__})")
|
print(f"✅ pymssql загружен (версия {pymssql.__version__})")
|
||||||
@@ -74,6 +136,9 @@ except ImportError:
|
|||||||
print(" pip install pymssql")
|
print(" pip install pymssql")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 5. Подключение к SQL Server
|
||||||
|
# ============================================================
|
||||||
try:
|
try:
|
||||||
conn = pymssql.connect(
|
conn = pymssql.connect(
|
||||||
server=DB_SERVER,
|
server=DB_SERVER,
|
||||||
@@ -90,7 +155,7 @@ except Exception as e:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 4. Проверка доступности таблиц
|
# 6. Проверка доступности таблиц
|
||||||
# ============================================================
|
# ============================================================
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
@@ -98,7 +163,7 @@ print(" Проверка доступности таблиц")
|
|||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
tables_to_check = [
|
tables_to_check = [
|
||||||
("UOV_SELFSERVICE_PR_EMP", "Таблица сотрудников (поиск по CARD_ID)"),
|
("UOV_SELFSERVICE_PR_EMP", "Таблица сотрудников"),
|
||||||
("UOV_SELFSERVICE_TB_TABEL", "Табель учёта рабочего времени"),
|
("UOV_SELFSERVICE_TB_TABEL", "Табель учёта рабочего времени"),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -110,14 +175,16 @@ for table, desc in tables_to_check:
|
|||||||
cols = [col[0] for col in cursor.description]
|
cols = [col[0] for col in cursor.description]
|
||||||
print(f"✅ {desc}")
|
print(f"✅ {desc}")
|
||||||
print(f" Таблица: {table}")
|
print(f" Таблица: {table}")
|
||||||
print(f" Столбцы: {', '.join(cols)}")
|
print(f" Столбцы: {', '.join(cols[:8])}")
|
||||||
|
if len(cols) > 8:
|
||||||
|
print(f" ... ещё {len(cols) - 8} столбцов")
|
||||||
else:
|
else:
|
||||||
print(f"⚠️ {desc} — таблица пуста")
|
print(f"⚠️ {desc} — таблица пуста")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ {desc} — ошибка: {e}")
|
print(f"❌ {desc} — ошибка: {e}")
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 5. Загрузка табеля за последние 5 месяцев
|
# 7. Загрузка табеля за последние 5 месяцев
|
||||||
# ============================================================
|
# ============================================================
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
@@ -127,8 +194,22 @@ print("=" * 60)
|
|||||||
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
|
||||||
while month <= 0:
|
while month <= 0:
|
||||||
@@ -139,21 +220,6 @@ for i in range(months_back):
|
|||||||
print(f"\n📅 {month_name} {year}")
|
print(f"\n📅 {month_name} {year}")
|
||||||
print("-" * 40)
|
print("-" * 40)
|
||||||
|
|
||||||
# Запрос 1: ищем EMP_ID по CARD_ID (тестовый — берём первого попавшегося)
|
|
||||||
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")
|
|
||||||
continue
|
|
||||||
emp_id = emp_row[0]
|
|
||||||
card_id = emp_row[1]
|
|
||||||
print(f" Тестовый сотрудник: emp_id={emp_id}, card_id={card_id}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f" ❌ Ошибка поиска сотрудника: {e}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Запрос 2: данные табеля
|
|
||||||
query = """
|
query = """
|
||||||
SELECT e.D, e.TDAY_ID, e.H
|
SELECT e.D, e.TDAY_ID, e.H
|
||||||
FROM UOV_SELFSERVICE_TB_TABEL e
|
FROM UOV_SELFSERVICE_TB_TABEL e
|
||||||
@@ -161,10 +227,10 @@ for i in range(months_back):
|
|||||||
ORDER BY e.D ASC
|
ORDER BY e.D ASC
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
cursor.execute(query, (emp_id, year, month))
|
cursor.execute(query, (test_emp_id, year, month))
|
||||||
records = cursor.fetchall()
|
records = cursor.fetchall()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ❌ Ошибка запроса табеля: {e}")
|
print(f" ❌ Ошибка запроса: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not records:
|
if not records:
|
||||||
@@ -173,54 +239,35 @@ for i in range(months_back):
|
|||||||
|
|
||||||
print(f" Записей: {len(records)}")
|
print(f" Записей: {len(records)}")
|
||||||
|
|
||||||
# Агрегация
|
|
||||||
total_days = 0
|
total_days = 0
|
||||||
total_hours = 0.0
|
total_hours = 0.0
|
||||||
codes = {}
|
codes = {}
|
||||||
|
|
||||||
for r in records:
|
for r in records:
|
||||||
day_date = r[0]
|
|
||||||
tday_id = str(r[1]).strip() if r[1] else "?"
|
tday_id = str(r[1]).strip() if r[1] else "?"
|
||||||
hours = float(r[2]) if r[2] is not None else 0.0
|
hours = float(r[2]) if r[2] is not None else 0.0
|
||||||
|
|
||||||
codes[tday_id] = codes.get(tday_id, 0) + 1
|
codes[tday_id] = codes.get(tday_id, 0) + 1
|
||||||
|
|
||||||
if tday_id == 'Я':
|
if tday_id == 'Я':
|
||||||
total_days += 1
|
total_days += 1
|
||||||
total_hours += hours
|
total_hours += hours
|
||||||
|
|
||||||
print(f" Явки (Я): {codes.get('Я', 0)} дн., всего часов: {total_hours:.1f}")
|
print(f" Явки (Я): {codes.get('Я', 0)} дн., часов: {total_hours:.1f}")
|
||||||
print(f" Коды дней: {', '.join(f'{k}={v}' for k, v in codes.items())}")
|
print(f" Коды: {', '.join(f'{k}={v}' for k, v in codes.items())}")
|
||||||
|
|
||||||
# Показываем первые 5 и последние 5 записей
|
|
||||||
print(f" Первые 5 записей:")
|
print(f" Первые 5 записей:")
|
||||||
for r in records[:5]:
|
for r in records[:5]:
|
||||||
d = r[0].strftime('%d.%m.%Y') if hasattr(r[0], 'strftime') else str(r[0])
|
d = r[0].strftime('%d.%m.%Y') if hasattr(r[0], 'strftime') else str(r[0])
|
||||||
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} ч.")
|
||||||
if len(records) > 5:
|
|
||||||
print(f" ... ещё {len(records) - 5} записей ...")
|
|
||||||
print(f" Последние 5 записей:")
|
|
||||||
for r in records[-5:]:
|
|
||||||
d = r[0].strftime('%d.%m.%Y') if hasattr(r[0], 'strftime') else str(r[0])
|
|
||||||
print(f" {d} | {str(r[1]).strip():>3} | {float(r[2]) if r[2] else 0:.1f} ч.")
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 6. Тест с конкретным CARD_ID пользователя
|
# 8. Тест с конкретным CARD_ID
|
||||||
# ============================================================
|
# ============================================================
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(" Тест с конкретным CARD_ID")
|
print(" Тест с конкретным CARD_ID")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
# Спрашиваем CARD_ID у пользователя
|
test_card_id = input("Введите CARD_ID (или Enter для теста с первым): ").strip()
|
||||||
test_card_id = input("Введите CARD_ID для проверки (или Enter для теста с первым): ").strip()
|
|
||||||
if not test_card_id:
|
|
||||||
# Берём первый
|
|
||||||
cursor.execute("SELECT TOP 1 CARD_ID FROM UOV_SELFSERVICE_PR_CARD ORDER BY ID")
|
|
||||||
row = cursor.fetchone()
|
|
||||||
test_card_id = str(row[0]).strip() if row else ""
|
|
||||||
print(f" Тестовый CARD_ID (первый): {test_card_id}")
|
|
||||||
|
|
||||||
if test_card_id:
|
if test_card_id:
|
||||||
print(f" Поиск сотрудника с CARD_ID={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,))
|
cursor.execute("SELECT e.ID FROM UOV_SELFSERVICE_PR_EMP e WHERE e.CARD_ID = %s", (test_card_id,))
|
||||||
@@ -230,22 +277,17 @@ if test_card_id:
|
|||||||
else:
|
else:
|
||||||
emp_id = row[0]
|
emp_id = row[0]
|
||||||
print(f" ✅ Найден: emp_id={emp_id}")
|
print(f" ✅ Найден: emp_id={emp_id}")
|
||||||
|
|
||||||
for i in range(min(3, months_back)):
|
for i in range(min(3, months_back)):
|
||||||
month = now.month - i
|
month = now.month - i
|
||||||
year = now.year
|
year = now.year
|
||||||
while month <= 0:
|
while month <= 0:
|
||||||
month += 12
|
month += 12
|
||||||
year -= 1
|
year -= 1
|
||||||
|
|
||||||
month_name = calendar.month_name[month]
|
month_name = calendar.month_name[month]
|
||||||
cursor.execute(query, (emp_id, year, month))
|
cursor.execute(query, (emp_id, year, month))
|
||||||
records = cursor.fetchall()
|
records = cursor.fetchall()
|
||||||
print(f" {month_name} {year}: {len(records)} записей")
|
print(f" {month_name} {year}: {len(records)} записей")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Закрытие
|
|
||||||
# ============================================================
|
|
||||||
conn.close()
|
conn.close()
|
||||||
print()
|
print()
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|||||||
Reference in New Issue
Block a user