feat(admin): add API endpoint to download order confirmation PDF securely as attachment
This commit is contained in:
53
shop/app/api/admin/orders/[id]/download/route.ts
Normal file
53
shop/app/api/admin/orders/[id]/download/route.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import { createAdminClient } from "@/lib/supabase/admin";
|
||||||
|
|
||||||
|
export async function GET(
|
||||||
|
request: NextRequest,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { id } = await params;
|
||||||
|
const adminDb = createAdminClient();
|
||||||
|
|
||||||
|
// 1. Get the order from database
|
||||||
|
const { data: order, error } = await adminDb
|
||||||
|
.from("orders")
|
||||||
|
.select("pdf_url, order_number")
|
||||||
|
.eq("id", id)
|
||||||
|
.single();
|
||||||
|
|
||||||
|
if (error || !order || !order.pdf_url) {
|
||||||
|
return new NextResponse("PDF not found", { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Determine file name in storage bucket
|
||||||
|
const storageFileName = `ab_${id}.pdf`;
|
||||||
|
|
||||||
|
// 3. Download file from Supabase storage
|
||||||
|
const { data: fileData, error: downloadError } = await adminDb
|
||||||
|
.storage
|
||||||
|
.from("invoices")
|
||||||
|
.download(storageFileName);
|
||||||
|
|
||||||
|
if (downloadError || !fileData) {
|
||||||
|
console.error("Failed to download PDF from storage:", downloadError);
|
||||||
|
return new NextResponse("Error downloading file from storage", { status: 500 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Return as attachment
|
||||||
|
const buffer = await fileData.arrayBuffer();
|
||||||
|
const downloadFileName = `Anfragebestaetigung_${order.order_number || id.slice(0, 8)}.pdf`;
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.append("Content-Disposition", `attachment; filename="${downloadFileName}"`);
|
||||||
|
headers.append("Content-Type", "application/pdf");
|
||||||
|
|
||||||
|
return new NextResponse(buffer, {
|
||||||
|
status: 200,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Download endpoint failed:", err);
|
||||||
|
return new NextResponse(err.message || "Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -224,7 +224,7 @@ export function OrdersTable({ initialOrders }: OrdersTableProps) {
|
|||||||
</a>
|
</a>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" size="sm" asChild className="h-8 text-xs">
|
<Button variant="secondary" size="sm" asChild className="h-8 text-xs">
|
||||||
<a href={order.pdf_url} download>
|
<a href={`/api/admin/orders/${order.id}/download`}>
|
||||||
<Download className="w-3.5 h-3.5" />
|
<Download className="w-3.5 h-3.5" />
|
||||||
</a>
|
</a>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user