From 874a24fbf5d22e4204a7479312b1ac0baa5e0ac1 Mon Sep 17 00:00:00 2001 From: drjones Date: Wed, 26 Aug 2026 16:37:30 -0700 Subject: [PATCH] security: gate analytics/orders/suppliers/customers behind admin JWT; sanitize public order tracking --- backend/app/routers/analytics.py | 3 ++- backend/app/routers/customers.py | 3 ++- backend/app/routers/orders.py | 9 +++++---- backend/app/routers/suppliers.py | 3 ++- backend/app/schemas.py | 12 ++++++++++++ 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/backend/app/routers/analytics.py b/backend/app/routers/analytics.py index 1462407..f741472 100644 --- a/backend/app/routers/analytics.py +++ b/backend/app/routers/analytics.py @@ -12,9 +12,10 @@ from sqlalchemy import func from sqlalchemy.orm import Session from app.database import get_db +from app.routers.auth import require_admin from app.models import Order, Supplier, SupplierPerformance -router = APIRouter() +router = APIRouter(dependencies=[Depends(require_admin)]) EXCLUDED = ["cancelled", "refunded"] diff --git a/backend/app/routers/customers.py b/backend/app/routers/customers.py index 3732591..7cf7767 100644 --- a/backend/app/routers/customers.py +++ b/backend/app/routers/customers.py @@ -10,10 +10,11 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.database import get_db +from app.routers.auth import require_admin from app.models import Customer from app.schemas import CustomerOut, CustomerRegister -router = APIRouter() +router = APIRouter(dependencies=[Depends(require_admin)]) @router.get("", response_model=List[CustomerOut]) diff --git a/backend/app/routers/orders.py b/backend/app/routers/orders.py index da1cc03..f288931 100644 --- a/backend/app/routers/orders.py +++ b/backend/app/routers/orders.py @@ -15,9 +15,10 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.database import get_db +from app.routers.auth import require_admin from app.engines.order_router import route_order from app.models import AuditLog, Customer, Order, Product -from app.schemas import OrderCreate, OrderOut, TrackingIn +from app.schemas import CustomerOrderOut, OrderCreate, OrderOut, TrackingIn router = APIRouter() @@ -79,20 +80,20 @@ def create_order(body: OrderCreate, db: Session = Depends(get_db)): @router.get("", response_model=List[OrderOut]) -def list_orders(status: Optional[str] = None, db: Session = Depends(get_db)): +def list_orders(status: Optional[str] = None, db: Session = Depends(get_db), _auth: dict = Depends(require_admin)): q = db.query(Order) if status: q = q.filter(Order.status == status) return q.order_by(Order.created_at.desc()).all() -@router.get("/{order_id}", response_model=OrderOut) +@router.get("/{order_id}", response_model=CustomerOrderOut) def get_order(order_id, db: Session = Depends(get_db)): return _get_order_or_404(db, order_id) @router.post("/{order_id}/tracking", response_model=OrderOut) -def add_tracking(order_id, body: TrackingIn, db: Session = Depends(get_db)): +def add_tracking(order_id, body: TrackingIn, db: Session = Depends(get_db), _auth: dict = Depends(require_admin)): order = _get_order_or_404(db, order_id) order.tracking = body.tracking if body.carrier: diff --git a/backend/app/routers/suppliers.py b/backend/app/routers/suppliers.py index f1d7488..90085bb 100644 --- a/backend/app/routers/suppliers.py +++ b/backend/app/routers/suppliers.py @@ -10,10 +10,11 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.database import get_db +from app.routers.auth import require_admin from app.models import Supplier, SupplierPerformance from app.schemas import SupplierCreate, SupplierOut, SupplierPerformanceOut -router = APIRouter() +router = APIRouter(dependencies=[Depends(require_admin)]) @router.get("", response_model=List[SupplierOut]) diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 2ef082a..2e62ff8 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -135,6 +135,18 @@ class OrderOut(ORMModel): updated_at: Optional[datetime] = None +class CustomerOrderOut(ORMModel): + id: UUID + order_number: str + items: Any + retail_total: float + status: str + tracking: Optional[str] = None + carrier: Optional[str] = None + created_at: Optional[datetime] = None + updated_at: Optional[datetime] = None + + class TrackingIn(BaseModel): tracking: str carrier: Optional[str] = None