import secrets from datetime import datetime, timezone import httpx from fastapi import APIRouter, Depends, Request from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from sqlalchemy.orm import Session from web.auth.session import get_current_user from web.config import settings from web.database import get_db from web.models.connections import EvotorConnection, VkConnection from web.templates_env import templates router = APIRouter() def _render(request: Request, template: str, ctx: dict) -> HTMLResponse: ctx["request"] = request ctx.setdefault("jivosite_widget_id", settings.JIVOSITE_WIDGET_ID) return templates.TemplateResponse(ctx.pop("request"), template, ctx) def _now() -> datetime: return datetime.now(timezone.utc).replace(tzinfo=None) @router.get("/connections") async def connections_get(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return RedirectResponse("/login", 303) evotor = db.query(EvotorConnection).filter_by(user_id=user.id).first() vk = db.query(VkConnection).filter_by(user_id=user.id).first() return _render(request, "connections.html", {"user": user, "evotor": evotor, "vk": vk}) @router.post("/connections/evotor") async def connections_evotor_post(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return RedirectResponse("/login", 303) form = await request.form() access_token = str(form.get("access_token", "")).strip() evotor_user_id = str(form.get("evotor_user_id", "")).strip() or None if not access_token: evotor = db.query(EvotorConnection).filter_by(user_id=user.id).first() return _render(request, "connections.html", { "user": user, "evotor": evotor, "errors": ["API-токен обязателен"], }) now = _now() conn = db.query(EvotorConnection).filter_by(user_id=user.id).first() if conn: conn.access_token = access_token if evotor_user_id: conn.evotor_user_id = evotor_user_id conn.updated_at = now else: conn = EvotorConnection( user_id=user.id, evotor_user_id=evotor_user_id, access_token=access_token, api_token=secrets.token_urlsafe(32), connected_at=now, updated_at=now, ) db.add(conn) if evotor_user_id and not user.evotor_user_id: user.evotor_user_id = evotor_user_id db.commit() return RedirectResponse("/connections?success=1", 303) @router.post("/connections/evotor/disconnect") async def connections_evotor_disconnect(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return RedirectResponse("/login", 303) conn = db.query(EvotorConnection).filter_by(user_id=user.id).first() if conn: db.delete(conn) db.commit() return RedirectResponse("/connections", 303) @router.post("/connections/vk") async def connections_vk_post(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return RedirectResponse("/login", 303) form = await request.form() access_token = str(form.get("access_token", "")).strip() vk_group_id = str(form.get("vk_group_id", "")).strip() or None if not access_token: evotor = db.query(EvotorConnection).filter_by(user_id=user.id).first() vk = db.query(VkConnection).filter_by(user_id=user.id).first() return _render(request, "connections.html", { "user": user, "evotor": evotor, "vk": vk, "errors": ["Токен VK обязателен"], }) now = _now() conn = db.query(VkConnection).filter_by(user_id=user.id).first() if conn: conn.access_token = access_token if vk_group_id: conn.vk_user_id = vk_group_id conn.updated_at = now else: conn = VkConnection( user_id=user.id, access_token=access_token, vk_user_id=vk_group_id, connected_at=now, updated_at=now, ) db.add(conn) db.commit() return RedirectResponse("/connections?success=1", 303) @router.post("/connections/vk/disconnect") async def connections_vk_disconnect(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return RedirectResponse("/login", 303) conn = db.query(VkConnection).filter_by(user_id=user.id).first() if conn: db.delete(conn) db.commit() return RedirectResponse("/connections", 303) @router.post("/connections/evotor/test") async def connections_evotor_test(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return JSONResponse({"ok": False, "message": "Не авторизован"}, status_code=401) conn = db.query(EvotorConnection).filter_by(user_id=user.id).first() if not conn: return JSONResponse({"ok": False, "message": "Подключение не настроено"}) try: r = httpx.get( "https://api.evotor.ru/stores", headers={ "Authorization": f"Bearer {conn.access_token}", "Accept": "application/vnd.evotor.v2+json", }, timeout=10, ) if r.status_code == 200: data = r.json() items = data.get("items", data) if isinstance(data, dict) else data count = len(items) if isinstance(items, list) else "?" return JSONResponse({"ok": True, "message": f"Успешно. Найдено магазинов: {count}"}) elif r.status_code == 401: return JSONResponse({"ok": False, "message": "Токен недействителен (401)"}) else: return JSONResponse({"ok": False, "message": f"Ошибка API: HTTP {r.status_code}"}) except httpx.TimeoutException: return JSONResponse({"ok": False, "message": "Таймаут запроса к Эвотор"}) except Exception as e: return JSONResponse({"ok": False, "message": f"Ошибка: {e}"}) @router.post("/connections/vk/test") async def connections_vk_test(request: Request, db: Session = Depends(get_db)): try: user = get_current_user(request, db) except Exception: return JSONResponse({"ok": False, "message": "Не авторизован"}, status_code=401) conn = db.query(VkConnection).filter_by(user_id=user.id).first() if not conn: return JSONResponse({"ok": False, "message": "Подключение не настроено"}) try: params = { "access_token": conn.access_token, "v": settings.VK_API_VERSION, } if conn.vk_user_id: params["group_ids"] = conn.vk_user_id r = httpx.get( "https://api.vk.com/method/groups.getById", params=params, timeout=10, ) data = r.json() if "error" in data: code = data["error"].get("error_code") msg = data["error"].get("error_msg", "Неизвестная ошибка") return JSONResponse({"ok": False, "message": f"Ошибка VK API ({code}): {msg}"}) groups = data.get("response", {}).get("groups", []) if groups: name = groups[0].get("name", "—") return JSONResponse({"ok": True, "message": f"Успешно. Сообщество: «{name}»"}) else: return JSONResponse({"ok": True, "message": "Токен действителен. Укажите ID сообщества для полной проверки."}) except httpx.TimeoutException: return JSONResponse({"ok": False, "message": "Таймаут запроса к VK"}) except Exception as e: return JSONResponse({"ok": False, "message": f"Ошибка: {e}"})