security: gate analytics/orders/suppliers/customers behind admin JWT; sanitize public order tracking

This commit is contained in:
drjones
2026-08-26 16:37:30 -07:00
parent e1addcc956
commit 874a24fbf5
5 changed files with 23 additions and 7 deletions

View File

@@ -12,9 +12,10 @@ from sqlalchemy import func
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.database import get_db from app.database import get_db
from app.routers.auth import require_admin
from app.models import Order, Supplier, SupplierPerformance from app.models import Order, Supplier, SupplierPerformance
router = APIRouter() router = APIRouter(dependencies=[Depends(require_admin)])
EXCLUDED = ["cancelled", "refunded"] EXCLUDED = ["cancelled", "refunded"]

View File

@@ -10,10 +10,11 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.database import get_db from app.database import get_db
from app.routers.auth import require_admin
from app.models import Customer from app.models import Customer
from app.schemas import CustomerOut, CustomerRegister from app.schemas import CustomerOut, CustomerRegister
router = APIRouter() router = APIRouter(dependencies=[Depends(require_admin)])
@router.get("", response_model=List[CustomerOut]) @router.get("", response_model=List[CustomerOut])

View File

@@ -15,9 +15,10 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.database import get_db from app.database import get_db
from app.routers.auth import require_admin
from app.engines.order_router import route_order from app.engines.order_router import route_order
from app.models import AuditLog, Customer, Order, Product 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() router = APIRouter()
@@ -79,20 +80,20 @@ def create_order(body: OrderCreate, db: Session = Depends(get_db)):
@router.get("", response_model=List[OrderOut]) @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) q = db.query(Order)
if status: if status:
q = q.filter(Order.status == status) q = q.filter(Order.status == status)
return q.order_by(Order.created_at.desc()).all() 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)): def get_order(order_id, db: Session = Depends(get_db)):
return _get_order_or_404(db, order_id) return _get_order_or_404(db, order_id)
@router.post("/{order_id}/tracking", response_model=OrderOut) @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 = _get_order_or_404(db, order_id)
order.tracking = body.tracking order.tracking = body.tracking
if body.carrier: if body.carrier:

View File

@@ -10,10 +10,11 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.database import get_db from app.database import get_db
from app.routers.auth import require_admin
from app.models import Supplier, SupplierPerformance from app.models import Supplier, SupplierPerformance
from app.schemas import SupplierCreate, SupplierOut, SupplierPerformanceOut from app.schemas import SupplierCreate, SupplierOut, SupplierPerformanceOut
router = APIRouter() router = APIRouter(dependencies=[Depends(require_admin)])
@router.get("", response_model=List[SupplierOut]) @router.get("", response_model=List[SupplierOut])

View File

@@ -135,6 +135,18 @@ class OrderOut(ORMModel):
updated_at: Optional[datetime] = None 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): class TrackingIn(BaseModel):
tracking: str tracking: str
carrier: Optional[str] = None carrier: Optional[str] = None