""" Надёжный сервис экспорта всей истории чата в JSON и Git. """ import json import logging import subprocess import os from pathlib import Path from datetime import datetime, timezone, timedelta from sqlalchemy import select, func from database.models import User, Message as DBMessage logger = logging.getLogger("ChatExporter") class ChatExporter: def __init__(self, session): self.session = session self.base_dir = Path(__file__).parent.parent self.export_dir = self.base_dir / "exports" self.export_dir.mkdir(exist_ok=True) self.uly_tz = timezone(timedelta(hours=4)) async def run_full_export(self): """Полный цикл: Генерация -> Запись в БД -> Push в Git""" try: now_local = datetime.now(self.uly_tz) timestamp = now_local.strftime("%Y-%m-%d_%H-%M") filename = f"chat_history_{timestamp}.json" filepath = self.export_dir / filename # 1. Собираем данные users_res = await self.session.execute(select(User)) users = users_res.scalars().all() msg_res = await self.session.execute(select(DBMessage).order_by(DBMessage.timestamp.asc())) messages = msg_res.scalars().all() export_data = { "info": { "exported_at": now_local.isoformat(), "total_users": len(list(users)), "total_messages": len(list(messages)) }, "users": [ { "id": u.user_id, "username": u.username, "name": u.full_name, "apt": u.apartment, "verified": u.verified } for u in users ], "messages": [ { "id": m.id, "user_id": m.user_id, "text": m.text, "date": m.timestamp.isoformat() if m.timestamp else None, "topic": m.topic } for m in messages ] } # 2. Сохраняем файл with open(filepath, "w", encoding="utf-8") as f: json.dump(export_data, f, ensure_ascii=False, indent=2) # 3. Пушим в Gitea git_success = self._push_to_gitea(filepath) # 4. Логируем в БД await self._log_to_db(filename, len(messages), git_success) return {"success": True, "filename": filename, "messages": len(messages), "git": git_success} except Exception as e: logger.error(f"❌ Критическая ошибка экспорта: {e}", exc_info=True) return {"success": False, "error": str(e)} def _push_to_gitea(self, filepath): """Отправка файла в Gitea через системный git""" try: # Напрямую, без прокси env = os.environ.copy() for var in ['http_proxy', 'https_proxy', 'all_proxy', 'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY']: env.pop(var, None) # Переходим в корень проекта для git команд os.chdir(str(self.base_dir)) subprocess.run(["git", "add", "-f", str(filepath)], check=True, env=env) subprocess.run(["git", "commit", "-m", f"📦 Авто-экспорт чата: {filepath.name}"], check=True, env=env) subprocess.run(["git", "push", "origin", "main"], check=True, env=env) logger.info(f"✅ Файл {filepath.name} успешно отправлен в Gitea") return True except Exception as e: logger.error(f"❌ Ошибка Git Push: {e}") return False async def _log_to_db(self, filename, count, git_pushed): from sqlalchemy import text try: # Используем текстовый запрос, так как у нас нет модели для этой таблицы sql = text("INSERT INTO chat_exports (filename, total_messages, git_pushed) VALUES (:f, :c, :g)") await self.session.execute(sql, {"f": filename, "c": count, "g": 1 if git_pushed else 0}) await self.session.commit() except Exception as e: logger.error(f"❌ Ошибка записи в таблицу экспортов: {e}") async def get_stats(self): """Получить статистику для веб-панели""" from sqlalchemy import text try: sql = text("SELECT COUNT(*), MAX(export_date) FROM chat_exports") res = await self.session.execute(sql) row = res.first() if row: count, last_date = row return {"total": count or 0, "last_date": last_date} return {"total": 0, "last_date": None} except Exception as e: logger.error(f"Error getting stats: {e}") return {"total": 0, "last_date": None}