feat: add connections dashboard with background health checks
- Add /connections page showing all integrations with online/offline status - Add background health checker that polls Evotor API every 10 minutes - Add is_online and last_checked_at fields to evotor_connections table - Replace Evotor navbar link with unified Connections link - Redirect connect/disconnect flows to /connections - Add Alembic migration for new columns Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
42
web/routes/connections.py
Normal file
42
web/routes/connections.py
Normal file
@@ -0,0 +1,42 @@
|
||||
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
|
||||
|
||||
router = APIRouter()
|
||||
templates = Jinja2Templates(directory="web/templates")
|
||||
|
||||
|
||||
@router.get("/connections")
|
||||
def connections_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()
|
||||
|
||||
connections = [
|
||||
{
|
||||
"name": "Эвотор",
|
||||
"icon": "bi-shop",
|
||||
"connected": evotor is not None,
|
||||
"is_online": evotor.is_online if evotor else False,
|
||||
"last_checked_at": evotor.last_checked_at if evotor else None,
|
||||
"details": evotor.store_name if evotor else None,
|
||||
"connect_url": "/evotor/connect",
|
||||
"disconnect_url": "/evotor/disconnect",
|
||||
}
|
||||
]
|
||||
|
||||
return templates.TemplateResponse("connections.html", {
|
||||
"request": request,
|
||||
"user": user,
|
||||
"connections": connections,
|
||||
})
|
||||
@@ -118,22 +118,27 @@ async def evotor_callback(
|
||||
pass # Store info is optional; token is still saved
|
||||
|
||||
# Save or update connection
|
||||
from datetime import datetime
|
||||
connection = db.query(EvotorConnection).filter(EvotorConnection.user_id == user.id).first()
|
||||
if connection:
|
||||
connection.access_token = access_token
|
||||
connection.store_id = store_id
|
||||
connection.store_name = store_name
|
||||
connection.is_online = True
|
||||
connection.last_checked_at = datetime.utcnow()
|
||||
else:
|
||||
connection = EvotorConnection(
|
||||
user_id=user.id,
|
||||
access_token=access_token,
|
||||
store_id=store_id,
|
||||
store_name=store_name,
|
||||
is_online=True,
|
||||
last_checked_at=datetime.utcnow(),
|
||||
)
|
||||
db.add(connection)
|
||||
db.commit()
|
||||
|
||||
return RedirectResponse("/evotor", 303)
|
||||
return RedirectResponse("/connections", 303)
|
||||
|
||||
|
||||
@router.post("/disconnect")
|
||||
@@ -150,4 +155,4 @@ async def evotor_disconnect(
|
||||
db.delete(connection)
|
||||
db.commit()
|
||||
|
||||
return RedirectResponse("/evotor", 303)
|
||||
return RedirectResponse("/connections", 303)
|
||||
|
||||
@@ -47,7 +47,7 @@ async def forgot_submit(request: Request, db: Session = Depends(get_db)):
|
||||
return templates.TemplateResponse("message.html", {
|
||||
"request": request, "user": None,
|
||||
"title": "Сброс пароля",
|
||||
"message": "Если аккаунт с таким email существует, ссылка для сброса пароля выведена в консоль сервера.",
|
||||
"message": "Если аккаунт с таким email существует, мы отправили письмо со ссылкой для сброса пароля.",
|
||||
})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user