Fix broker reconnect dashboard redirect
This commit is contained in:
parent
b5b759c5ed
commit
a90603f4f6
@ -1,5 +1,6 @@
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from urllib.parse import urlsplit, urlunsplit
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query, Request
|
||||
from fastapi.responses import RedirectResponse
|
||||
@ -53,6 +54,7 @@ from app.services.zerodha_storage import (
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/broker")
|
||||
DEFAULT_PRODUCTION_DASHBOARD_URL = "https://app.quantfortune.com/dashboard?armed=false"
|
||||
|
||||
|
||||
def _require_user(request: Request):
|
||||
@ -72,6 +74,31 @@ def _require_session_id(request: Request) -> str:
|
||||
return session_id
|
||||
|
||||
|
||||
def _build_broker_dashboard_url(request: Request) -> str:
|
||||
configured_dashboard = (os.getenv("BROKER_DASHBOARD_URL") or "").strip()
|
||||
if configured_dashboard:
|
||||
return configured_dashboard
|
||||
|
||||
app_base_url = (os.getenv("APP_BASE_URL") or "").strip()
|
||||
if app_base_url:
|
||||
return f"{app_base_url.rstrip('/')}/dashboard?armed=false"
|
||||
|
||||
base_url = str(request.base_url).rstrip("/")
|
||||
parsed = urlsplit(base_url)
|
||||
hostname = (parsed.hostname or "").strip().lower()
|
||||
scheme = parsed.scheme or "https"
|
||||
|
||||
if hostname in {"localhost", "127.0.0.1"}:
|
||||
return f"{scheme}://{hostname}:5173/dashboard?armed=false"
|
||||
|
||||
if hostname.startswith("api.") and len(hostname) > 4:
|
||||
scheme = "https"
|
||||
frontend_netloc = parsed.netloc.replace(hostname, f"app.{hostname[4:]}", 1)
|
||||
return urlunsplit((scheme, frontend_netloc, "/dashboard", "armed=false", ""))
|
||||
|
||||
return DEFAULT_PRODUCTION_DASHBOARD_URL
|
||||
|
||||
|
||||
def _first_number(*values, default: float = 0.0) -> float:
|
||||
for value in values:
|
||||
try:
|
||||
@ -654,7 +681,7 @@ async def broker_callback(request: Request, request_token: str = "", state: str
|
||||
broker_user_id=session_data.get("user_id"),
|
||||
auth_state="VALID",
|
||||
)
|
||||
target_url = os.getenv("BROKER_DASHBOARD_URL") or "/dashboard?armed=false"
|
||||
target_url = _build_broker_dashboard_url(request)
|
||||
return RedirectResponse(target_url)
|
||||
|
||||
|
||||
|
||||
@ -173,6 +173,103 @@ def test_wrong_or_expired_broker_callback_state_fails(monkeypatch):
|
||||
assert response.json() == {"detail": "Invalid or expired broker callback state"}
|
||||
|
||||
|
||||
def test_reconnect_callback_redirects_to_app_dashboard_by_default(monkeypatch):
|
||||
import app.main as app_main
|
||||
import app.routers.broker as broker_router
|
||||
|
||||
monkeypatch.setenv("APP_ENV", "test")
|
||||
monkeypatch.setenv("DISABLE_STARTUP_TASKS", "1")
|
||||
monkeypatch.setenv("CORS_ORIGINS", "http://localhost:3000")
|
||||
monkeypatch.delenv("BROKER_DASHBOARD_URL", raising=False)
|
||||
monkeypatch.delenv("APP_BASE_URL", raising=False)
|
||||
importlib.reload(app_main)
|
||||
app = app_main.create_app()
|
||||
client = TestClient(app)
|
||||
|
||||
monkeypatch.setattr(broker_router, "get_user_for_session", lambda _sid: {"id": "user-1", "username": "user@example.com"})
|
||||
monkeypatch.setattr(
|
||||
broker_router,
|
||||
"consume_broker_callback_state",
|
||||
lambda **kwargs: {"id": "state-1", "expires_at": datetime.now(timezone.utc).isoformat()},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
broker_router,
|
||||
"get_broker_credentials",
|
||||
lambda _user_id: {"api_key": "kite-key", "api_secret": "kite-secret"},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
broker_router,
|
||||
"exchange_request_token",
|
||||
lambda api_key, api_secret, token: {
|
||||
"access_token": "access-token",
|
||||
"request_token": token,
|
||||
"user_name": "Trader",
|
||||
"user_id": "Z123",
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(broker_router, "set_zerodha_session", lambda user_id, payload: None)
|
||||
monkeypatch.setattr(broker_router, "set_connected_broker", lambda user_id, broker, token, **kwargs: None)
|
||||
|
||||
response = client.get(
|
||||
"/api/broker/callback",
|
||||
params={"request_token": "request-token", "state": "valid-state"},
|
||||
cookies={"session_id": "session-1"},
|
||||
follow_redirects=False,
|
||||
headers={"host": "api.quantfortune.com"},
|
||||
)
|
||||
|
||||
assert response.status_code == 307
|
||||
assert response.headers["location"] == "https://app.quantfortune.com/dashboard?armed=false"
|
||||
|
||||
|
||||
def test_reconnect_callback_uses_configured_dashboard_url(monkeypatch):
|
||||
import app.main as app_main
|
||||
import app.routers.broker as broker_router
|
||||
|
||||
monkeypatch.setenv("APP_ENV", "test")
|
||||
monkeypatch.setenv("DISABLE_STARTUP_TASKS", "1")
|
||||
monkeypatch.setenv("CORS_ORIGINS", "http://localhost:3000")
|
||||
monkeypatch.setenv("BROKER_DASHBOARD_URL", "https://app.quantfortune.com/dashboard?armed=false")
|
||||
importlib.reload(app_main)
|
||||
app = app_main.create_app()
|
||||
client = TestClient(app)
|
||||
|
||||
monkeypatch.setattr(broker_router, "get_user_for_session", lambda _sid: {"id": "user-1", "username": "user@example.com"})
|
||||
monkeypatch.setattr(
|
||||
broker_router,
|
||||
"consume_broker_callback_state",
|
||||
lambda **kwargs: {"id": "state-1", "expires_at": datetime.now(timezone.utc).isoformat()},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
broker_router,
|
||||
"get_broker_credentials",
|
||||
lambda _user_id: {"api_key": "kite-key", "api_secret": "kite-secret"},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
broker_router,
|
||||
"exchange_request_token",
|
||||
lambda api_key, api_secret, token: {
|
||||
"access_token": "access-token",
|
||||
"request_token": token,
|
||||
"user_name": "Trader",
|
||||
"user_id": "Z123",
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(broker_router, "set_zerodha_session", lambda user_id, payload: None)
|
||||
monkeypatch.setattr(broker_router, "set_connected_broker", lambda user_id, broker, token, **kwargs: None)
|
||||
|
||||
response = client.get(
|
||||
"/api/broker/callback",
|
||||
params={"request_token": "request-token", "state": "valid-state"},
|
||||
cookies={"session_id": "session-1"},
|
||||
follow_redirects=False,
|
||||
headers={"host": "api.quantfortune.com"},
|
||||
)
|
||||
|
||||
assert response.status_code == 307
|
||||
assert response.headers["location"] == "https://app.quantfortune.com/dashboard?armed=false"
|
||||
|
||||
|
||||
def test_broker_callback_state_service_rejects_wrong_user_and_expired_state(monkeypatch):
|
||||
import app.services.broker_callback_state as callback_state
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user