From 4b314d65ba6f3ce53c4c9c06f4053d466be98d78 Mon Sep 17 00:00:00 2001 From: s4luorth Date: Thu, 1 Oct 2026 14:01:35 +0200 Subject: [PATCH] Fix Mitarbeiter-Uebersicht: keine directus_users-Abhaengigkeit + api_clients-Leserecht Mitarbeiter (Staff-Rolle) sah nichts + keine Suche: Order-Abfrage forderte customer.company (directus_users) UND api_client.name (api_clients) an - beide fuer Staff nicht lesbar -> 403 -> ganze Abfrage scheitert. - customer.* aus der Uebersicht-Abfrage entfernt (Name kommt aus api_client); kundeName nutzt nur noch api_client.name - Order-Abfrage 3-stufig robust (mit kuvertieren+client -> ohne kuvertieren -> ohne client), jobs/machines-Fetch mit Feld-Fallback -> Ansicht laedt auch ohne Bootstrap - Bootstrap: Staff darf api_clients lesen (nur id+name, keine Secrets) Fuer die API-Kundennamen Bootstrap laufen lassen; die Ansicht selbst geht schon nach Extension-Deploy. Co-Authored-By: Claude Opus 4.8 --- bootstrap/bootstrap.mjs | 3 ++ .../dist/index.js | 35 +++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/bootstrap/bootstrap.mjs b/bootstrap/bootstrap.mjs index bb0a3ff..1ff6d2d 100644 --- a/bootstrap/bootstrap.mjs +++ b/bootstrap/bootstrap.mjs @@ -1252,6 +1252,9 @@ async function applyPermissions() { for (const col of BIZ) for (const act of ['create', 'read', 'update', 'delete']) await ensurePermission(staffPol.id, col, act); + // Mitarbeiter-Übersicht zeigt API-Kundennamen bei Sammelaufträgen (Chargen) – + // nur id + name lesen, NICHT die Token/Secrets des Zugangs. + await ensurePermission(staffPol.id, 'api_clients', 'read', ['id', 'name']); // Customer: nur Eigenes + Lesen der Kataloge // Alt-Namen auf den finalen "Kunde" ziehen (idempotent). diff --git a/extensions/directus-extension-skrift-uebersicht/dist/index.js b/extensions/directus-extension-skrift-uebersicht/dist/index.js index c1cd01e..a5bcfaf 100644 --- a/extensions/directus-extension-skrift-uebersicht/dist/index.js +++ b/extensions/directus-extension-skrift-uebersicht/dist/index.js @@ -65,7 +65,9 @@ const Board = { const sucheTyp = ref('brief'); const aktiveMaschinen = computed(() => machines.value.filter((m) => m.active !== false)); - function kundeName(o) { return [o.customer?.company, [o.customer?.first_name, o.customer?.last_name].filter(Boolean).join(' ')].filter(Boolean).join(' · '); } + // Mitarbeiter-Ansicht liest keine directus_users-Felder (Rechte) → Name aus + // API-Kunde; manuelle Aufträge zeigen sonst Auftragsname/-nummer. + function kundeName(o) { return o.api_client?.name || ''; } // „Seite 1" o. Ä. = Seiten eines mehrseitigen Briefs, kein Empfänger. const istSeitenmarker = (z) => /^seite\s*\d+$/i.test(String(z || '').trim()); function freitextName(ft) { @@ -86,16 +88,29 @@ const Board = { if (!leise) { loading.value = true; err.value = ''; } try { const [o, j, m, t] = await Promise.all([ - api.get('/items/orders', { params: { - limit: -1, sort: 'date_created', - filter: { production_status: { _in: AKTIV_STATUS } }, - fields: 'id,order_number,order_name,production_status,needs_envelope,kuvertieren,brief_gedruckt,kuvert_gedruckt,frankiert,' + (async () => { + // Sichere Basisfelder (alle auf orders/formats/products – von der + // Mitarbeiter-Rolle lesbar). api_client (API-Kundenname) und kuvertieren + // sind optional: fehlende Rechte/Felder dürfen die Ansicht NICHT blockieren. + const basis = 'id,order_number,order_name,production_status,needs_envelope,brief_gedruckt,kuvert_gedruckt,frankiert,' + 'format.key,format.name,shipping_day,shipping_type,versanddatum,date_created,entries_count,source,' - + 'envelope_labeling,envelope_format,api_client.id,api_client.name,product.name,' - + 'customer.first_name,customer.last_name,customer.company', - } }), - api.get('/items/jobs', { params: { limit: -1, sort: '-priority,position,date_created', filter: { status: { _in: ['queued', 'printing'] } }, fields: 'id,type,status,format,format_label,position,machine.id,order.id,order.order_number' } }).catch(() => ({ data: { data: [] } })), - api.get('/items/machines', { params: { limit: -1, filter: { active: { _eq: true } }, fields: 'id,name,current_format,pending_format,status,active' } }).catch(() => ({ data: { data: [] } })), + + 'envelope_labeling,envelope_format,product.name'; + const mitClient = basis + ',api_client.id,api_client.name'; + const p = (fields) => ({ limit: -1, sort: 'date_created', filter: { production_status: { _in: AKTIV_STATUS } }, fields }); + try { return await api.get('/items/orders', { params: p(mitClient + ',kuvertieren') }); } + catch { + try { return await api.get('/items/orders', { params: p(mitClient) }); } + catch { return await api.get('/items/orders', { params: p(basis) }); } + } + })(), + (async () => { + try { return await api.get('/items/jobs', { params: { limit: -1, sort: '-priority,position,date_created', filter: { status: { _in: ['queued', 'printing'] } }, fields: 'id,type,status,format,format_label,position,machine.id,order.id,order.order_number' } }); } + catch { try { return await api.get('/items/jobs', { params: { limit: -1, filter: { status: { _in: ['queued', 'printing'] } }, fields: 'id,type,status,format,format_label,machine.id,order.id' } }); } catch { return { data: { data: [] } }; } } + })(), + (async () => { + try { return await api.get('/items/machines', { params: { limit: -1, filter: { active: { _eq: true } }, fields: 'id,name,current_format,pending_format,status,active' } }); } + catch { try { return await api.get('/items/machines', { params: { limit: -1, filter: { active: { _eq: true } }, fields: 'id,name,current_format,status,active' } }); } catch { return { data: { data: [] } }; } } + })(), api.get('/items/format_templates', { params: { limit: -1, fields: 'id,key,name,type,default_format,search_default' } }).catch(() => ({ data: { data: [] } })), ]); const vorherAnzahl = orders.value.length;