diff --git a/backend/app/api/routers/notifications.py b/backend/app/api/routers/notifications.py index be5c8c6..bf6db81 100644 --- a/backend/app/api/routers/notifications.py +++ b/backend/app/api/routers/notifications.py @@ -9,6 +9,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, func, update, or_, and_ from app.database import get_db +from app.domains.auth.models import PM_ROLES from app.models.audit_log import AuditLog from app.models.user import User from app.utils.auth import get_current_user @@ -45,7 +46,7 @@ class MarkReadRequest(BaseModel): def _visibility_filter(user: User): """Rows visible to this user: targeted at them, or broadcast (null) if admin/PM.""" targeted = AuditLog.target_user_id == user.id - if user.role.value in ("admin", "project_manager"): + if user.role.value in PM_ROLES: broadcast = AuditLog.target_user_id.is_(None) return and_(AuditLog.notification == True, or_(targeted, broadcast)) # noqa: E712 return and_(AuditLog.notification == True, targeted) # noqa: E712 diff --git a/backend/app/api/routers/order_items.py b/backend/app/api/routers/order_items.py index bc630e3..b794b0b 100644 --- a/backend/app/api/routers/order_items.py +++ b/backend/app/api/routers/order_items.py @@ -14,6 +14,7 @@ from app.models.cad_file import CadFile from app.models.order import Order, OrderStatus from app.models.order_item import OrderItem, ItemStatus from app.models.user import User +from app.domains.auth.models import PM_ROLES from app.schemas.order import OrderItemOut from app.utils.auth import get_current_user @@ -25,7 +26,7 @@ router = APIRouter(prefix="/orders", tags=["order_items"]) # --------------------------------------------------------------------------- def _is_privileged(user: User) -> bool: - return user.role.value in ("admin", "project_manager") + return user.role.value in PM_ROLES async def _get_order_and_item( diff --git a/backend/app/api/routers/orders.py b/backend/app/api/routers/orders.py index dfd2a06..18028ce 100644 --- a/backend/app/api/routers/orders.py +++ b/backend/app/api/routers/orders.py @@ -24,6 +24,7 @@ from app.models.product import Product from app.models.output_type import OutputType from app.models.cad_file import CadFile from app.models.user import User +from app.domains.auth.models import PM_ROLES from app.schemas.order import OrderCreate, OrderOut, OrderDetailOut, OrderItemOut, RejectOrderRequest from app.schemas.order_line import OrderLineCreate, OrderLineOut from app.schemas.product import ProductOut @@ -35,7 +36,7 @@ router = APIRouter(prefix="/orders", tags=["orders"]) def _is_privileged(user: User) -> bool: - return user.role.value in ("admin", "project_manager") + return user.role.value in PM_ROLES def _result_path_to_url(result_path: str) -> str | None: diff --git a/backend/app/api/routers/uploads.py b/backend/app/api/routers/uploads.py index f3af2d5..20f1f70 100644 --- a/backend/app/api/routers/uploads.py +++ b/backend/app/api/routers/uploads.py @@ -10,6 +10,7 @@ from pydantic import BaseModel from app.config import settings from app.database import get_db +from app.domains.auth.models import PM_ROLES from app.models.cad_file import CadFile, ProcessingStatus from app.models.order import Order from app.models.order_item import OrderItem @@ -491,7 +492,7 @@ async def add_material_alias_from_validation( from app.domains.materials.models import Material, MaterialAlias # Gate to admin/PM - if user.role.value not in ("admin", "project_manager"): + if user.role.value not in PM_ROLES: raise HTTPException(status_code=403, detail="Admin or project_manager required") # Verify the validation exists diff --git a/backend/app/domains/admin/dashboard_service.py b/backend/app/domains/admin/dashboard_service.py index a1943e6..058cfb7 100644 --- a/backend/app/domains/admin/dashboard_service.py +++ b/backend/app/domains/admin/dashboard_service.py @@ -10,6 +10,7 @@ from datetime import datetime from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession +from app.domains.auth.models import PM_ROLES from app.domains.admin.models import DashboardConfig logger = logging.getLogger(__name__) @@ -59,7 +60,7 @@ def get_default_widgets_for_role(role: str) -> list[dict]: admin / project_manager: KPI + analytics defaults. client: RecentRenders + ProductionStats only. """ - if role in ("admin", "project_manager"): + if role in PM_ROLES: return [w.copy() for w in _DEFAULT_ADMIN_WIDGETS] return [w.copy() for w in _DEFAULT_CLIENT_WIDGETS] diff --git a/frontend/src/api/orders.ts b/frontend/src/api/orders.ts index 67f0fa2..6f482cf 100644 --- a/frontend/src/api/orders.ts +++ b/frontend/src/api/orders.ts @@ -2,6 +2,8 @@ import api from './client' import type { Product } from './products' import type { OutputType } from './outputTypes' +const DEFAULT_ORDER_LIMIT = 200 + export interface RenderLog { renderer?: string type?: string @@ -132,7 +134,12 @@ export interface OrderDetail extends Order { } export async function listOrders(params?: { status?: string; skip?: number; limit?: number }) { - const res = await api.get('/orders', { params }) + const res = await api.get('/orders', { + params: { + ...params, + limit: params?.limit ?? DEFAULT_ORDER_LIMIT, + }, + }) return res.data } @@ -149,7 +156,7 @@ export async function searchOrders(params: { statuses: params.statuses?.join(',') || '', date_from: params.date_from || '', date_to: params.date_to || '', - limit: params.limit || 50, + limit: params.limit ?? DEFAULT_ORDER_LIMIT, }, }) return res.data