ea7fffa3a1
- Add SubscriptionPlan model and subscription_plans table (migration 015) - Add billing cycle/period/allow_overage fields to UserProfile (migration 016) - Add subscription_overage_percent config field (replaces overage_factor) - Rewrite check_upload_allowed: use overage_percent, yearly carry-over, no daily cap - Add seed_default_plans(), _plan_to_dict(), get_year_file_count(), _months_elapsed() - Update get_tier/get_all_tiers to be DB-first with TIER_DEFAULTS fallback - Add TIER_DEFAULTS alias (TIERS kept for backward compat) - New /api/plans/ CRUD endpoints (admin-only except list/get) - New /admin/plans Plan Designer page with Alpine.js UI - Add Plan Designer link to admin navigation in base.html - Remove 'Files per day' row from pricing comparison table - Add billing cycle + period start to admin users edit modal - Seed default plans on startup in lifespan handler - Rewrite docs/SubscriptionTiers.md with full plan/overage/API docs - Fix all tests in test_subscription.py (remove daily cap tests, add overage/carry-over tests) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
"""View routes for subscription-related pages.
|
|
|
|
Routes:
|
|
GET /pricing — public marketing pricing page
|
|
GET /subscription — authenticated user's current plan & usage
|
|
"""
|
|
|
|
import logging
|
|
|
|
from fastapi import Depends, Request
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.utils.subscription import TIER_ORDER, get_all_tiers, get_tier, get_user_tier_id, get_user_usage
|
|
from app.views.base import APIRouter, get_db, require_login, templates
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/pricing", include_in_schema=False)
|
|
async def pricing_page(request: Request, db: Session = Depends(get_db)):
|
|
"""Public-facing pricing and plans page."""
|
|
tiers = get_all_tiers(db)
|
|
return templates.TemplateResponse(
|
|
"pricing.html",
|
|
{
|
|
"request": request,
|
|
"tiers": tiers,
|
|
"tier_order": TIER_ORDER,
|
|
},
|
|
)
|
|
|
|
|
|
@router.get("/subscription", include_in_schema=False)
|
|
@require_login
|
|
async def my_subscription_page(request: Request, db: Session = Depends(get_db)):
|
|
"""Authenticated user's subscription status and usage page."""
|
|
from app.config import settings
|
|
|
|
user = request.session.get("user") or {}
|
|
owner_id: str = user.get("username") or user.get("email") or user.get("sub") or ""
|
|
|
|
if settings.multi_user_enabled and owner_id:
|
|
tier_id = get_user_tier_id(db, owner_id)
|
|
usage = get_user_usage(db, owner_id)
|
|
else:
|
|
tier_id = "business"
|
|
usage = None
|
|
|
|
tier = get_tier(tier_id, db)
|
|
all_tiers = get_all_tiers(db)
|
|
|
|
return templates.TemplateResponse(
|
|
"subscription.html",
|
|
{
|
|
"request": request,
|
|
"tier": tier,
|
|
"tier_id": tier_id,
|
|
"usage": usage,
|
|
"all_tiers": all_tiers,
|
|
"multi_user_enabled": settings.multi_user_enabled,
|
|
"owner_id": owner_id,
|
|
},
|
|
)
|