From e2d92a031f280b56a7a07aa76f709305a5e69be9 Mon Sep 17 00:00:00 2001 From: DanielS Date: Wed, 15 Jul 2026 16:14:31 +0200 Subject: [PATCH] feat(licserver): add partner customers proxy API --- shop/app/admin/einstellungen/page.tsx | 144 +++++++++--------- .../partners/[id]/customers/route.ts | 85 +++++++++++ shop/lib/types/licserver.ts | 57 +++++++ 3 files changed, 212 insertions(+), 74 deletions(-) create mode 100644 shop/app/api/licserver/partners/[id]/customers/route.ts diff --git a/shop/app/admin/einstellungen/page.tsx b/shop/app/admin/einstellungen/page.tsx index 80b8c0b..319a72c 100644 --- a/shop/app/admin/einstellungen/page.tsx +++ b/shop/app/admin/einstellungen/page.tsx @@ -21,14 +21,14 @@ export default function AdminSettings() { const [loading, setLoading] = useState(true); // LicServer Config State - const [licUrl, setLicUrl] = useState(''); - const [licKey, setLicKey] = useState(''); - const [showKey, setShowKey] = useState(false); - const [licSaving, setLicSaving] = useState(false); - const [licTesting, setLicTesting] = useState(false); - const [licStatus, setLicStatus] = useState<{ ok: boolean; message: string } | null>(null); - const [licMsg, setLicMsg] = useState(''); - const [licMsgType, setLicMsgType] = useState<'success' | 'error' | ''>(''); + const [licUrl, setLicUrl] = useState(''); + const [licKey, setLicKey] = useState(''); + const [showKey, setShowKey] = useState(false); + const [licSaving, setLicSaving] = useState(false); + const [licTesting, setLicTesting] = useState(false); + const [licStatus, setLicStatus] = useState<{ ok: boolean; message: string } | null>(null); + const [licMsg, setLicMsg] = useState(''); + const [licMsgType, setLicMsgType] = useState<'success' | 'error' | ''>(''); const router = useRouter(); useEffect(() => { @@ -63,7 +63,7 @@ export default function AdminSettings() { .single(); if (licRow) { setLicUrl(licRow.licserver_base_url || ''); - setLicKey(licRow.licserver_api_key || ''); + setLicKey(licRow.licserver_api_key || ''); } } catch (dbErr) { console.error("Fehler beim Laden der LicServer-Einstellungen:", dbErr); @@ -90,7 +90,7 @@ export default function AdminSettings() { try { const res = await fetch('/api/admin/db-backup'); if (!res.ok) throw new Error('Export fehlgeschlagen'); - + const blob = await res.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); @@ -184,11 +184,10 @@ export default function AdminSettings() { {statusMsg && ( -
+ 'bg-blue-500/10 border-blue-500/20 text-blue-600 dark:text-blue-400' + }`}> {statusMsg}
)} @@ -205,8 +204,8 @@ export default function AdminSettings() { Lädt alle Kategorien, Produkte, Module, Firmen, Endkunden, Bestellungen und SMTP-Einstellungen als ZIP-Datei herunter.

- -

Wird als X-Api-Key Header an den LicServer gesendet

+ + - - {/* Actions */} -
- + {/* Actions */} +
+ - +
- ); } + diff --git a/shop/app/api/licserver/partners/[id]/customers/route.ts b/shop/app/api/licserver/partners/[id]/customers/route.ts new file mode 100644 index 0000000..5101128 --- /dev/null +++ b/shop/app/api/licserver/partners/[id]/customers/route.ts @@ -0,0 +1,85 @@ +import { NextRequest, NextResponse } from 'next/server' +import { createClient } from '@/lib/supabase/server' +import { getLicServerConfig } from '@/lib/actions/licserver-config' +import type { CustomerDtoPagedResult, LicServerProblemDetails } from '@/lib/types/licserver' + +/** + * GET /api/licserver/partners/[id]/customers + * + * Proxy to LicServer GET /api-v1/partners/{id}/customers + * [id] must be a valid UUID. + * Query params forwarded: search, page, pageSize + * + * Secured: requires a valid Supabase session. + * base_url + api_key are read from DB settings (admin-configurable), + * with fallback to LICSERVER_BASE_URL / LICSERVER_API_KEY env vars. + */ +export async function GET( + req: NextRequest, + { params }: { params: Promise<{ id: string }> } +) { + // ── Auth guard ───────────────────────────────────────────────────────── + const supabase = await createClient() + const { data: { user } } = await supabase.auth.getUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + + // ── Load config from DB (falls back to env vars) ────────────────────── + const cfg = await getLicServerConfig() + if (!cfg.base_url || !cfg.api_key) { + console.error('[licserver] base_url or api_key not configured (DB or env)') + return NextResponse.json( + { error: 'LicServer nicht konfiguriert. Bitte in den Admin-Einstellungen hinterlegen.' }, + { status: 503 } + ) + } + + const { id } = await params + + // Basic UUID format guard + const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i + if (!UUID_RE.test(id)) { + return NextResponse.json({ error: 'Invalid partner ID' }, { status: 400 }) + } + + // ── Forward query params ─────────────────────────────────────────────── + const { searchParams } = req.nextUrl + const upstream = new URL(`${cfg.base_url}/api-v1/partners/${id}/customers`) + const search = searchParams.get('search') + const page = searchParams.get('page') + const pageSize = searchParams.get('pageSize') + if (search) upstream.searchParams.set('search', search) + if (page) upstream.searchParams.set('page', page) + if (pageSize) upstream.searchParams.set('pageSize', pageSize) + + // ── Proxy request ────────────────────────────────────────────────────── + try { + const res = await fetch( + upstream.toString(), + { + method: 'GET', + headers: { + 'X-Api-Key': cfg.api_key, + 'Accept': 'application/json', + }, + signal: AbortSignal.timeout(5_000), + } + ) + + if (!res.ok) { + const problem: LicServerProblemDetails = await res.json().catch(() => ({})) + return NextResponse.json(problem, { status: res.status }) + } + + const data: CustomerDtoPagedResult = await res.json() + return NextResponse.json(data) + + } catch (err) { + console.error('[licserver] partner/:id/customers fetch error:', err) + return NextResponse.json( + { error: 'LicServer nicht erreichbar' }, + { status: 502 } + ) + } +} diff --git a/shop/lib/types/licserver.ts b/shop/lib/types/licserver.ts index eddb2c3..273c4b7 100644 --- a/shop/lib/types/licserver.ts +++ b/shop/lib/types/licserver.ts @@ -29,3 +29,60 @@ export interface LicServerProblemDetails { instance?: string | null [key: string]: unknown } + +export interface CustomerDto { + id: string // UUID + name: string | null + street: string | null + houseNumber: string | null + houseNumberAddon: string | null + zipCode: string | null + city: string | null + countryCode: string | null + email: string | null + partnerId: string | null + erpId: string | null +} + +export interface CustomerDtoPagedResult { + page: number + pageSize: number + totalCount: number + totalPages: number + hasNextPage: boolean + hasPreviousPage: boolean + items: CustomerDto[] | null +} + +export interface LocationDto { + id: string // UUID + name: string | null + street: string | null + houseNumber: string | null + houseNumberAddon: string | null + countryCode: string | null + postalCode: string | null + city: string | null + taxNumber: string | null + vatIdNumber: string | null +} + +export interface CustomerDetailsDto { + id: string // UUID + name: string | null + street: string | null + houseNumber: string | null + houseNumberAddon: string | null + zipCode: string | null + city: string | null + countryCode: string | null + email: string | null + partnerId: string | null + erpId: string | null + partnerName: string | null + taxNumber: string | null + vatIdNumber: string | null + notes: string | null + locations: LocationDto[] | null +} +