Fix broker session showing connected after Zerodha token expiry

- Set connected=FALSE (was TRUE) when expiring broker session so the
  dashboard correctly reflects disconnected state
- Notify user by email when their Zerodha session expires so they know
  to reconnect before the next SIP execution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thigazhezhilan J 2026-05-01 13:38:45 +05:30
parent 247a1c5107
commit 1b14e7b23e
2 changed files with 19 additions and 8 deletions

View File

@ -162,7 +162,7 @@ def expire_user_broker_session(user_id: str):
cur.execute(
"""
UPDATE user_broker
SET connected = TRUE,
SET connected = FALSE,
access_token = NULL,
auth_state = 'EXPIRED'
WHERE user_id = %s

View File

@ -5,6 +5,7 @@ from fastapi.responses import HTMLResponse
from app.broker_store import expire_user_broker_session
from app.services.auth_service import get_user_for_session
from app.services.email_service import send_email_async
from app.services.live_equity_service import (
capture_live_equity_snapshot,
get_live_equity_curve,
@ -48,14 +49,24 @@ def _capture_request_token(request: Request, request_token: str):
store_request_token(user["id"], token)
def _clear_broker_session(user_id: str):
def _clear_broker_session(user_id: str, email: str | None = None):
expire_user_broker_session(user_id)
clear_session(user_id)
if email:
try:
body = (
"Your Zerodha session has expired and your broker connection has been disconnected.\n\n"
"Please log in to QuantFortune and reconnect your Zerodha account to resume your strategy.\n\n"
"If your strategy was running, it has been paused until you reconnect."
)
send_email_async(email, "Action required: Zerodha session expired", body)
except Exception:
pass
def _raise_kite_error(user_id: str, exc: KiteApiError):
def _raise_kite_error(user_id: str, exc: KiteApiError, email: str | None = None):
if isinstance(exc, KiteTokenError):
_clear_broker_session(user_id)
_clear_broker_session(user_id, email=email)
raise HTTPException(
status_code=401, detail="Zerodha session expired. Please reconnect."
) from exc
@ -139,7 +150,7 @@ async def holdings(request: Request):
try:
data = fetch_holdings(session["api_key"], session["access_token"])
except KiteApiError as exc:
_raise_kite_error(user["id"], exc)
_raise_kite_error(user["id"], exc, email=user["username"])
return {"holdings": [normalize_holding(item) for item in data]}
@ -152,7 +163,7 @@ async def funds(request: Request):
try:
data = fetch_funds(session["api_key"], session["access_token"])
except KiteApiError as exc:
_raise_kite_error(user["id"], exc)
_raise_kite_error(user["id"], exc, email=user["username"])
equity = data.get("equity", {}) if isinstance(data, dict) else {}
return {"funds": {**equity, "raw": data}}
@ -168,7 +179,7 @@ async def equity_curve(request: Request, from_: str = Query("", alias="from")):
holdings = fetch_holdings(session["api_key"], session["access_token"])
funds_data = fetch_funds(session["api_key"], session["access_token"])
except KiteApiError as exc:
_raise_kite_error(user["id"], exc)
_raise_kite_error(user["id"], exc, email=user["username"])
try:
capture_live_equity_snapshot(
@ -177,7 +188,7 @@ async def equity_curve(request: Request, from_: str = Query("", alias="from")):
funds_data=funds_data,
)
except KiteApiError as exc:
_raise_kite_error(user["id"], exc)
_raise_kite_error(user["id"], exc, email=user["username"])
now = datetime.utcnow()
default_start = (now - timedelta(days=90)).date()