mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
set up presigned urls api
This commit is contained in:
parent
03e8ad00e6
commit
fd7c1578ef
3 changed files with 72 additions and 37 deletions
57
src/app/api/upload/due-considerations/route.ts
Normal file
57
src/app/api/upload/due-considerations/route.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import S3 from "aws-sdk/clients/s3";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
|
||||
const presignedUrlSchema = z.object({
|
||||
files: z.array(
|
||||
z.object({
|
||||
fileKey: z.string(),
|
||||
contentType: z.string(),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const body = await request.json();
|
||||
let validatedBody;
|
||||
|
||||
try {
|
||||
validatedBody = presignedUrlSchema.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.PRSIGN_AWS_ACCESS_KEY,
|
||||
secretAccessKey: process.env.PRESIGN_AWS_SECRET_KEY,
|
||||
});
|
||||
|
||||
const { files } = validatedBody;
|
||||
// generate a presigned URL for each file
|
||||
const preSignedUrls = await Promise.all(
|
||||
files.map(async (file: any) => {
|
||||
return s3.getSignedUrlPromise("putObject", {
|
||||
Bucket: process.env.RETOFIT_PLAN_INPUT_BUCKET_NAME,
|
||||
Key: file.fileKey,
|
||||
ContentType: file.contentType,
|
||||
Expires: 5 * 60,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
return new NextResponse(JSON.stringify({ url: preSignedUrls }), {
|
||||
status: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return new NextResponse(JSON.stringify({ msg: "Internal server error" }), {
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -4,41 +4,14 @@ import { Input } from "@/app/shadcn_components/ui/input";
|
|||
import { Label } from "@/app/shadcn_components/ui/label";
|
||||
|
||||
export function SelectFolder({
|
||||
handleButtonDisabled,
|
||||
setUploadMessage,
|
||||
setFile,
|
||||
handleOnChange,
|
||||
}: {
|
||||
handleButtonDisabled: (file?: File[]) => void;
|
||||
setUploadMessage: (message: string) => void;
|
||||
setFile: (file: File[]) => void;
|
||||
handleOnChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}) {
|
||||
function handleOnChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
if (e.target.files && e.target.files.length === 3) {
|
||||
const files = Array.from(e.target.files);
|
||||
const extensions = files.map((file) =>
|
||||
file.name.split(".").pop()?.toLowerCase()
|
||||
);
|
||||
|
||||
if (
|
||||
extensions.includes("xml") &&
|
||||
extensions.includes("pdf") &&
|
||||
extensions.includes("docx")
|
||||
) {
|
||||
setFile(files); // You would need to update setFile to accept an array of files
|
||||
handleButtonDisabled(files); // Similarly, update handleButtonDisabled to work with multiple files
|
||||
} else {
|
||||
setUploadMessage("Please select a .xml, .pdf, and .docx file.");
|
||||
}
|
||||
} else {
|
||||
setUploadMessage("Please select exactly 3 files.");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
id="folder-uploader"
|
||||
type="file"
|
||||
// TODO: Handle accept - we want a folder
|
||||
accept=".xml,.pdf,.docx"
|
||||
multiple={true}
|
||||
className="cursor-pointer"
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import { SelectFolder } from "../components/due-considerations/SelectFolder";
|
|||
import { Button } from "../shadcn_components/ui/button";
|
||||
|
||||
export default function DueConsiderationsHome() {
|
||||
const [file, setFile] = useState<File[]>([]);
|
||||
const [files, setFile] = useState<File[]>([]);
|
||||
const [buttonDisabled, setButtonDisabled] = useState(true);
|
||||
const [uploadMessage, setUploadMessage] = useState("");
|
||||
|
||||
function handleButtonDisabled(files?: File[]) {
|
||||
if (files && files.length === 3) {
|
||||
const extensions = files.map((file) =>
|
||||
function handleOnChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
if (e.target.files && e.target.files.length === 3) {
|
||||
const filesArray = Array.from(e.target.files);
|
||||
const extensions = filesArray.map((file) =>
|
||||
file.name.split(".").pop()?.toLowerCase()
|
||||
);
|
||||
|
||||
|
|
@ -20,7 +21,9 @@ export default function DueConsiderationsHome() {
|
|||
extensions.includes("pdf") &&
|
||||
extensions.includes("docx")
|
||||
) {
|
||||
setFile(files);
|
||||
setButtonDisabled(false);
|
||||
setUploadMessage("");
|
||||
} else {
|
||||
setUploadMessage("Please select a .xml, .pdf, and .docx file.");
|
||||
setButtonDisabled(true);
|
||||
|
|
@ -31,6 +34,10 @@ export default function DueConsiderationsHome() {
|
|||
}
|
||||
}
|
||||
|
||||
function onUpload() {
|
||||
// We want to upload the files to s3 via a presigned link
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center mt-20 tracking-wider leading-loose">
|
||||
<div className="text-center">
|
||||
|
|
@ -45,10 +52,7 @@ export default function DueConsiderationsHome() {
|
|||
</div>
|
||||
|
||||
<div className="mb-5">
|
||||
<SelectFolder
|
||||
handleButtonDisabled={handleButtonDisabled}
|
||||
setFile={setFile}
|
||||
/>
|
||||
<SelectFolder handleOnChange={handleOnChange} />
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between w-full">
|
||||
|
|
@ -56,6 +60,7 @@ export default function DueConsiderationsHome() {
|
|||
<Button
|
||||
disabled={buttonDisabled}
|
||||
className="bg-brandblue hover:bg-hoverblue"
|
||||
onClick={onUpload}
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue