Fix #2+#3: Routes API 404 et conflit blueprint name
Bug #2: portal_server.py importait api_v1_bp depuis saas_api_v1 au lieu de api_v1/__init__.py. Tous les sous-blueprints api_v1/routes/* (health, courses, predictions, valuebets, backtest, export, metrics, ml_feedback) n'etaient jamais enregistres -> 404. Fix: utiliser register_api_v1(app) depuis api_v1/__init__.py. Bug #3: Conflit de nom de blueprint entre saas_api_v1 et api_v1 (tous deux nommes api_v1). Renomme le blueprint de saas_api_v1 en saas_api_v1_bp. Supprime les record_once handlers de saas_api_v1 qui dupliquaient l'enregistrement de sous-blueprints (billing, org, user, history) - desormais geres par register_api_v1(app). Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -13,7 +13,7 @@ from saas_auth import require_auth
|
||||
|
||||
DB_PATH = os.environ.get("TURF_SAAS_DB", "/home/h3r7/turf_saas/turf_saas.db")
|
||||
|
||||
api_v1_bp = Blueprint("api_v1", __name__, url_prefix="/api/v1")
|
||||
saas_api_v1_bp = Blueprint("saas_api_v1", __name__, url_prefix="/api/v1")
|
||||
|
||||
|
||||
def get_db():
|
||||
@@ -30,7 +30,7 @@ def plan_allows(user_plan: str, required: str) -> bool:
|
||||
# ─── Stats ────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@api_v1_bp.route("/stats/summary", methods=["GET"])
|
||||
@saas_api_v1_bp.route("/stats/summary", methods=["GET"])
|
||||
@require_auth
|
||||
def stats_summary():
|
||||
"""GET /api/v1/stats/summary — résumé dashboard."""
|
||||
@@ -94,7 +94,7 @@ def stats_summary():
|
||||
# ─── Predictions ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@api_v1_bp.route("/predictions/today", methods=["GET"])
|
||||
@saas_api_v1_bp.route("/predictions/today", methods=["GET"])
|
||||
@require_auth
|
||||
def predictions_today():
|
||||
"""GET /api/v1/predictions/today — prédictions du jour selon le plan."""
|
||||
@@ -149,7 +149,7 @@ def predictions_today():
|
||||
return jsonify({"error": str(e), "predictions": []}), 200
|
||||
|
||||
|
||||
@api_v1_bp.route("/predictions/race/<race_label>", methods=["GET"])
|
||||
@saas_api_v1_bp.route("/predictions/race/<race_label>", methods=["GET"])
|
||||
@require_auth
|
||||
def predictions_race(race_label):
|
||||
"""GET /api/v1/predictions/race/<label> — prédictions d'une course."""
|
||||
@@ -187,7 +187,7 @@ def predictions_race(race_label):
|
||||
# ─── Value Bets ───────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@api_v1_bp.route("/value-bets/today", methods=["GET"])
|
||||
@saas_api_v1_bp.route("/value-bets/today", methods=["GET"])
|
||||
@require_auth
|
||||
def value_bets_today():
|
||||
"""GET /api/v1/value-bets/today — value bets (Premium+)."""
|
||||
@@ -220,7 +220,7 @@ def value_bets_today():
|
||||
# ─── Export ───────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@api_v1_bp.route("/export/csv", methods=["GET"])
|
||||
@saas_api_v1_bp.route("/export/csv", methods=["GET"])
|
||||
@require_auth
|
||||
def export_csv():
|
||||
"""GET /api/v1/export/csv — export CSV (Pro only)."""
|
||||
@@ -257,15 +257,13 @@ def export_csv():
|
||||
)
|
||||
|
||||
|
||||
# ─── Billing Blueprint (Stripe) + JWT init — HRT-49 ─────────────────────────
|
||||
# Registers /api/v1/billing/* routes via nested Blueprint (Flask 2.0+)
|
||||
# Also initializes JWTManager on the Flask app (required for jwt_required_middleware)
|
||||
# ─── JWT init — HRT-49 ────────────────────────────────────────────────────────
|
||||
# Initialize JWTManager on the Flask app (required for jwt_required_middleware)
|
||||
# Called when saas_api_v1_bp is registered (portal_server.py)
|
||||
try:
|
||||
from flask_jwt_extended import JWTManager
|
||||
from api_v1.routes.billing import billing_bp
|
||||
|
||||
# Initialize JWTManager on the Flask app when api_v1_bp is registered
|
||||
@api_v1_bp.record_once
|
||||
@saas_api_v1_bp.record_once
|
||||
def _init_jwt(state):
|
||||
app = state.app
|
||||
if not app.config.get("JWT_SECRET_KEY"):
|
||||
@@ -276,57 +274,6 @@ try:
|
||||
)
|
||||
if "flask_jwt_extended" not in app.extensions:
|
||||
JWTManager(app)
|
||||
|
||||
# Register billing blueprint with url_prefix='/billing'
|
||||
# (parent api_v1_bp has '/api/v1', so result is /api/v1/billing/*)
|
||||
api_v1_bp.register_blueprint(billing_bp, url_prefix="/billing")
|
||||
print("[saas_api_v1] Billing blueprint (Stripe) + JWT registered ✅")
|
||||
except Exception as _billing_err:
|
||||
print(f"[saas_api_v1] Warning: billing blueprint not loaded: {_billing_err}")
|
||||
|
||||
|
||||
# ─── Org Blueprint — HRT-82 ───────────────────────────────────────────────────
|
||||
# Registers /api/v1/org/* routes (Pro plan only, multi-compte max 5 users)
|
||||
try:
|
||||
from api_v1.routes.org import org_bp
|
||||
|
||||
@api_v1_bp.record_once
|
||||
def _register_org_bp(state):
|
||||
app = state.app
|
||||
app.register_blueprint(org_bp)
|
||||
|
||||
print("[saas_api_v1] Org blueprint (multi-compte Pro) registered ✅")
|
||||
except Exception as _org_err:
|
||||
print(f"[saas_api_v1] Warning: org blueprint not loaded: {_org_err}")
|
||||
|
||||
|
||||
# ─── User Blueprint — HRT-79 (Telegram) + HRT-80 (API Token + Webhook) ───────
|
||||
# Registers /api/v1/user/* routes (Premium+ for telegram, Pro for api-token/webhook)
|
||||
try:
|
||||
from api_v1.routes.user import user_bp
|
||||
from api_v1.routes.user_tokens import user_tokens_bp
|
||||
|
||||
@api_v1_bp.record_once
|
||||
def _register_user_bp(state):
|
||||
app = state.app
|
||||
app.register_blueprint(user_bp)
|
||||
app.register_blueprint(user_tokens_bp)
|
||||
|
||||
print('[saas_api_v1] User blueprint (Telegram config + API token + Webhook) registered ✅')
|
||||
except Exception as _user_err:
|
||||
print(f'[saas_api_v1] Warning: user blueprints not loaded: {_user_err}')
|
||||
|
||||
|
||||
# ─── History Blueprint — HRT-81 ───────────────────────────────────────────────
|
||||
# Registers /api/v1/history route (Free:7j, Premium:90j, Pro:illimité)
|
||||
try:
|
||||
from api_v1.routes.history import history_bp
|
||||
|
||||
@api_v1_bp.record_once
|
||||
def _register_history_bp(state):
|
||||
app = state.app
|
||||
app.register_blueprint(history_bp)
|
||||
|
||||
print('[saas_api_v1] History blueprint (plan-limited history) registered ✅')
|
||||
except Exception as _history_err:
|
||||
print(f'[saas_api_v1] Warning: history blueprint not loaded: {_history_err}')
|
||||
print("[saas_api_v1] JWT init registered ✅")
|
||||
except Exception as _jwt_err:
|
||||
print(f"[saas_api_v1] Warning: JWT init not loaded: {_jwt_err}")
|
||||
|
||||
Reference in New Issue
Block a user