From 3268cf210073adf386ec461b63b280bfdc4e7150 Mon Sep 17 00:00:00 2001 From: BOHA Date: Tue, 9 Jun 2026 20:59:06 +0200 Subject: [PATCH] fix(nas): order PDF archive uses orders.view (parity w/ invoices) + document NAS_INVOICES/NAS_ORDERS Review follow-ups: the ?save=1 archive route required orders.export while the save that triggers it only needs orders.edit, so an editor's fire-and-forget archive 403'd silently. Use requireAnyPermission(orders.view, orders.export) to match invoices-pdf (invoices.view). Also refresh .env.example for the split vars. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 3 ++- src/routes/admin/issued-orders-pdf.ts | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index e1110d3..4d2bc07 100644 --- a/.env.example +++ b/.env.example @@ -37,7 +37,8 @@ REFRESH_TOKEN_REMEMBER_EXPIRY=2592000 # ── File storage (NAS network shares) ───────────────────────────────────── NAS_PATH=Z:/02_PROJEKTY -# NAS_FINANCIALS_PATH= +# NAS_INVOICES= # invoice PDFs — {base}/Vydané|Přijaté/YYYY/MM/ (falls back to NAS_FINANCIALS_PATH if unset) +# NAS_ORDERS= # issued-order PDF archival — {base}/Vydané/YYYY/MM/ (off until set) # NAS_OFFERS_PATH= MAX_UPLOAD_SIZE=52428800 # 50 MB diff --git a/src/routes/admin/issued-orders-pdf.ts b/src/routes/admin/issued-orders-pdf.ts index 88d1c50..5b1271d 100644 --- a/src/routes/admin/issued-orders-pdf.ts +++ b/src/routes/admin/issued-orders-pdf.ts @@ -1,6 +1,6 @@ import { FastifyInstance } from "fastify"; import prisma from "../../config/database"; -import { requirePermission } from "../../middleware/auth"; +import { requireAnyPermission } from "../../middleware/auth"; import { parseId, success } from "../../utils/response"; import { localDateCzStr } from "../../utils/date"; import { htmlToPdf } from "../../utils/html-to-pdf"; @@ -821,7 +821,12 @@ ${indentCSS} export default async function issuedOrdersPdfRoutes(fastify: FastifyInstance) { fastify.get<{ Params: { id: string } }>( "/:id", - { preHandler: requirePermission("orders.export") }, + // Mirror invoices-pdf (invoices.view): view-level access serves both the + // user-facing Export PDF and the ?save=1 NAS archive. Using requireAny so an + // order editor (who has orders.view) can trigger archival on save without + // also needing orders.export — otherwise the fire-and-forget archive 403s + // silently. orders.export holders keep access too. + { preHandler: requireAnyPermission("orders.view", "orders.export") }, async (request, reply) => { const id = parseId(request.params.id, reply); if (id === null) return;