presign api working but want to use temp aws credentials|

This commit is contained in:
Khalim Conn-Kowlessar 2024-09-09 14:52:34 +01:00
parent 8147a0d4b7
commit 07be8eaf84
2 changed files with 84 additions and 19 deletions

View file

@ -0,0 +1,49 @@
// pages/api/get-presigned-url.ts
import S3 from "aws-sdk/clients/s3";
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
const PresignedUrlBodySchema = z.object({
fileKey: z.string(),
});
export async function POST(request: NextRequest) {
const body = await request.json();
let validatedBody;
try {
validatedBody = PresignedUrlBodySchema.parse(body);
} catch (error) {
console.error("Invalid input: ", error);
return new NextResponse(JSON.stringify({ msg: "Invalid input" }), {
status: 400,
});
}
try {
const s3 = new S3({
signatureVersion: "v4",
region: process.env.PRESIGN_AWS_REGION,
accessKeyId: process.env.RETROFIT_ENERGY_ASSESSMENTS_AWS_ACCESS_KEY,
secretAccessKey: process.env.ENERGY_ASSESSMENTS_AWS_SECRET,
});
const { fileKey } = validatedBody;
// Presigned URL is valid for 5 minutes
const preSignedUrl = await s3.getSignedUrl("getObject", {
Bucket: process.env.RETROFIT_ENERGY_ASSESSMENTS_BUCKET,
Key: fileKey,
Expires: 5 * 60,
});
return new NextResponse(JSON.stringify({ url: preSignedUrl }), {
status: 200,
});
} catch (error) {
console.error(error);
return new NextResponse(JSON.stringify({ msg: "Internal server error" }), {
status: 500,
});
}
}

View file

@ -8,13 +8,14 @@ import {
TableRow,
} from "@/app/shadcn_components/ui/table";
import { BrandBlueButton } from "@/app/components/Buttons";
import { useMutation } from "@tanstack/react-query";
import { DocumentType } from "@/app/db/schema/energy_assessments";
// Use the type directly from the array
type Document = {
id: bigint;
documentType: (typeof DocumentType)[number]; // Create a union type from the array
documentLocation: string;
documentLocation: string; // S3 file key
uploadedAt: Date;
};
@ -35,6 +36,21 @@ const descriptions: { [key in (typeof DocumentType)[number]]: string } = {
"Scenario Site Notes": "Site notes from the scenario analysis",
};
// Fetch the presigned URL from the API
async function generatePresignedUrl(fileKey: string) {
const response = await fetch("/api/energy-assessment-documents", {
method: "POST",
body: JSON.stringify({ fileKey }),
});
if (!response.ok) {
throw new Error("Failed to generate presigned URL");
}
const data = await response.json();
return data.url;
}
export const DocumentsTable: React.FC<Props> = ({
documents,
allowedTypes,
@ -43,38 +59,38 @@ export const DocumentsTable: React.FC<Props> = ({
allowedTypes.includes(doc.documentType)
);
// Track displayed descriptions
const displayedDescriptions: Record<(typeof DocumentType)[number], boolean> =
allowedTypes.reduce((acc, type) => {
acc[type] = false;
return acc;
}, {} as Record<(typeof DocumentType)[number], boolean>);
const processedDocuments = relevantDocuments.map((doc) => {
const showDescription = !displayedDescriptions[doc.documentType];
if (showDescription) {
displayedDescriptions[doc.documentType] = true;
// Mutation to handle the presigned URL generation
const { mutate: fetchPresignedUrl } = useMutation(
async (fileKey: string) => await generatePresignedUrl(fileKey),
{
onSuccess: (url) => {
window.open(url, "_blank"); // Open the file in a new tab
},
onError: (error) => {
console.error("Error generating presigned URL:", error);
},
}
return { ...doc, showDescription };
});
);
const handleDownload = (documentLocation: string) => {
fetchPresignedUrl(documentLocation); // Generate URL and open in new tab
};
return (
<Table className="min-w-full divide-y divide-gray-200 shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<TableBody className="bg-white divide-y divide-gray-200">
{processedDocuments.map((doc) => (
{relevantDocuments.map((doc) => (
<TableRow key={doc.id.toString()}>
<TableCell className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{doc.documentType}
</TableCell>
<TableCell className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{doc.showDescription ? descriptions[doc.documentType] : ""}
{descriptions[doc.documentType] || ""}
</TableCell>
<TableCell className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<BrandBlueButton
label="Download"
onClick={() =>
console.log(`Downloading ${doc.documentLocation}`)
}
onClick={() => handleDownload(doc.documentLocation)} // Call the download handler
/>
</TableCell>
</TableRow>