import { fetchBillById } from '@/app/lib/actions/billActions'; import { notFound } from 'next/navigation'; import { extractShareId, validateShareChecksum } from '@/app/lib/shareChecksum'; import { getDbClient } from '@/app/lib/dbClient'; import { BillingLocation } from '@/app/lib/db-types'; export async function GET(request: Request, { params: { id } }: { params: { id: string } }) { // Parse shareId-billID format // shareId = 40 chars (locationId 24 + checksum 16) const shareId = id.substring(0, 40); const billID = id.substring(41); // Skip the '-' separator if (!shareId || !billID) { notFound(); } // Validate shareId and extract locationId const extracted = extractShareId(shareId); if (!extracted) { notFound(); } const { locationId: locationID, checksum } = extracted; // Validate checksum if (!validateShareChecksum(locationID, checksum)) { notFound(); } // Check TTL before fetching bill const dbClient = await getDbClient(); const location = await dbClient.collection("lokacije") .findOne({ _id: locationID }, { projection: { shareTTL: 1 } }); if (!location) { notFound(); } // Check if sharing is active and not expired if (!location.shareTTL || new Date() > location.shareTTL) { notFound(); } const [_, bill] = await fetchBillById(locationID, billID, true) ?? []; if (!bill?.attachment) { notFound(); } // convert fileContentsBase64 from Base64 string to binary string const fileContentsBuffer = Buffer.from(bill.attachment.fileContentsBase64, 'base64'); // convert fileContentsBuffer to format that can be sent to the client const fileContents = new Uint8Array(fileContentsBuffer); return new Response(fileContents, { status: 200, headers: { 'Content-Type': "application/octet-stream", 'Content-Disposition': `attachment; filename="${bill.attachment.fileName}"`, 'Last-Modified': `${bill.attachment.fileLastModified}` } }); }