Files
evo-sync/web/routes/sync.py
mguschin 9aeef73b10 feat: release v1.8.0 — connections dashboard, VK OAuth, sync config, catalog browser
- Connections dashboard with add/remove flow and background health checks
- VK OAuth connection with profile info and health monitoring
- Sync configuration page with master toggle and filter summary
- Catalog browser with store/group/product tables, filter management, CSV export
- Alembic migrations for all new tables
- run/read_config.py for shell sync script DB integration
- CHANGELOG.md updated for v1.8.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:08:19 +03:00

103 lines
2.9 KiB
Python

from datetime import datetime
from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from web.auth import get_current_user
from web.database import get_db
from web.models import User, EvotorConnection, VkConnection, SyncConfig, SyncFilter
router = APIRouter(prefix="/sync")
templates = Jinja2Templates(directory="web/templates")
def _get_or_create_sync_config(db: Session, user_id: int) -> SyncConfig:
config = db.query(SyncConfig).filter(SyncConfig.user_id == user_id).first()
if not config:
config = SyncConfig(user_id=user_id, is_enabled=False)
db.add(config)
db.commit()
db.refresh(config)
return config
def _filter_summary(config: SyncConfig) -> dict:
stores = [f for f in config.filters if f.entity_type == "store"]
groups = [f for f in config.filters if f.entity_type == "group"]
products = [f for f in config.filters if f.entity_type == "product"]
return {
"stores": len(stores),
"groups": len(groups),
"products": len(products),
"total": len(config.filters),
}
@router.get("")
def sync_page(
request: Request,
db: Session = Depends(get_db),
user: User | None = Depends(get_current_user),
):
if not user:
return RedirectResponse("/login", 303)
evotor = db.query(EvotorConnection).filter(EvotorConnection.user_id == user.id).first()
vk = db.query(VkConnection).filter(VkConnection.user_id == user.id).first()
config = _get_or_create_sync_config(db, user.id)
summary = _filter_summary(config)
if config.confirmed_at and config.is_enabled:
status = "active"
elif config.confirmed_at and not config.is_enabled:
status = "paused"
elif summary["total"] > 0:
status = "pending"
else:
status = "unconfigured"
return templates.TemplateResponse("sync.html", {
"request": request,
"user": user,
"evotor": evotor,
"vk": vk,
"config": config,
"summary": summary,
"status": status,
})
@router.post("/toggle")
def sync_toggle(
request: Request,
db: Session = Depends(get_db),
user: User | None = Depends(get_current_user),
):
if not user:
return RedirectResponse("/login", 303)
config = _get_or_create_sync_config(db, user.id)
config.is_enabled = not config.is_enabled
db.commit()
return RedirectResponse("/sync", 303)
@router.post("/confirm")
def sync_confirm(
request: Request,
db: Session = Depends(get_db),
user: User | None = Depends(get_current_user),
):
if not user:
return RedirectResponse("/login", 303)
config = _get_or_create_sync_config(db, user.id)
if config.is_enabled and len(config.filters) > 0:
config.confirmed_at = datetime.utcnow()
db.commit()
return RedirectResponse("/sync", 303)