Skip to content

Commit

Permalink
#9: attempt to support Hearings as well as JCTs
Browse files Browse the repository at this point in the history
  • Loading branch information
mmarcotte committed Sep 9, 2024
1 parent 7a28fbb commit e88272f
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 25 deletions.
13 changes: 11 additions & 2 deletions app/actions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
"use server";

import { getSignedUrlForUpload } from "@/lib/getSignedUrlForUpload";
import { DocType } from "@/types/DocType";

export async function startUpload({ filename }: { filename: string }) {
const result = await getSignedUrlForUpload({ filename });
export async function startUpload({
filename,
folderName,
docType
}: {
filename: string,
folderName: string,
docType: DocType
}) {
const result = await getSignedUrlForUpload({ filename, folderName, docType });
return result.url;
}
4 changes: 2 additions & 2 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default function Home() {
return (
<SessionProvider>
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
<div className="flex-col">
<div className="z-10 max-w-5xl w-full justify-between font-mono text-sm lg:flex">
<div className="flex-col py-10">
<div>
<Image
src="/images/library-books.svg"
Expand Down
56 changes: 39 additions & 17 deletions components/UploadForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useInput } from "@/hooks/useInput";
import { MouseEventHandler, useEffect, useState, useTransition } from "react";
import { useSession } from "next-auth/react";
import { startUpload } from "@/app/actions";
import { DocType } from "@/types/DocType";

export default function Component() {
const { data: session } = useSession();

Expand All @@ -18,7 +20,7 @@ export default function Component() {
return (
<div>
{session?.user?.email &&
usersWhoCanLogin.includes(session.user.email.toLowerCase()) ? (
usersWhoCanLogin.includes(session.user.email.toLowerCase()) ? (
<div>
<UploadForm />
</div>
Expand All @@ -40,6 +42,7 @@ const UploadForm = () => {
const [isUploadComplete, setIsUploadComplete] = useState(false);
const [isDisabled, setDisabled] = useState(true);
const [url, setUrl] = useState("");
const [docType, setDocType] = useState<DocType>("JCT");

const fixFilename = (fn: string) => {
const [basename, extension] = fn.split(".");
Expand All @@ -48,9 +51,9 @@ const UploadForm = () => {
};

const uploadFile = () => {
console.log("upload file clicked");
initUpload(async () => {
const url = await startUpload({ filename: `${foldername}/${filename}` });

const url = await startUpload({ docType, filename, folderName: foldername });

await fetch(url, {
method: "PUT",
Expand Down Expand Up @@ -78,8 +81,12 @@ const UploadForm = () => {
}, [files.value, kohaNumber.value]);

useEffect(() => {
const docUrl = docType === "JCT" ?
`${process.env.NEXT_PUBLIC_S3_JCT_URL_PREFIX}/${foldername}/${filename}`
: `${process.env.NEXT_PUBLIC_S3_HEARINGS_URL_PREFIX}/${filename}`

setUrl(
`${process.env.NEXT_PUBLIC_S3_URL_PREFIX}/${foldername}/${filename}`
docUrl
);
}, [filename, foldername]);

Expand All @@ -101,15 +108,31 @@ const UploadForm = () => {
<input className="text-slate-800 p-2" type="text" {...kohaNumber} />
</div>
<div className="flex flex-col gap-2">
<label>Folder Name</label>
<input
className="text-slate-800 p-2 max-w-5xl w-full"
type="text"
value={foldername}
disabled={isDisabled}
readOnly
/>
<label>Type</label>
<div className="flex flex-row gap-2">
<button className={`btn ${docType === "JCT" ? "btn-blue" : "btn-disabled"}`} onClick={() => setDocType("JCT")}>
JCT
</button>
<button
className={`btn ${docType === "Hearing" ? "btn-blue" : "btn-disabled"}`}
onClick={() => setDocType("Hearing")}
>
Hearings
</button>
</div>
</div>
{docType === "JCT" && (
<div className="flex flex-col gap-2">
<label>Folder Name</label>
<input
className="text-slate-800 p-2 max-w-5xl w-full"
type="text"
value={foldername}
disabled={isDisabled}
readOnly
/>
</div>
)}
<div className="flex flex-col gap-2">
<label>Filename</label>
<input
Expand Down Expand Up @@ -165,11 +188,10 @@ const Upload = ({
}) => {
return (
<button
className={`btn ${
isDisabled
? "btn-disabled cursor-not-allowed"
: "btn-blue cursor-pointer"
}`}
className={`btn ${isDisabled
? "btn-disabled cursor-not-allowed"
: "btn-blue cursor-pointer"
}`}
disabled={isDisabled}
onClick={onClick}
>
Expand Down
16 changes: 14 additions & 2 deletions lib/getSignedUrlForUpload.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { DocType } from "@/types/DocType";

export type PersistenceGetSignedUrlForUploadResult = {
url: string;
};

export type PersistenceGetSignedUrlForUpload = ({
filename,
folderName,
docType
}: {
filename: string;
folderName?: string;
docType: DocType;

}) => Promise<PersistenceGetSignedUrlForUploadResult>;

export const getSignedUrlForUpload: PersistenceGetSignedUrlForUpload = async ({
filename,
folderName,
docType
}) => {

const Key = docType === "JCT" ? `${folderName}/${filename}` : filename;
const Bucket = docType === "JCT" ? process.env.S3_BUCKET_JCT : process.env.S3_BUCKET_HEARINGS;

const client = new S3Client({
region: "us-east-1",
credentials: {
Expand All @@ -24,8 +36,8 @@ export const getSignedUrlForUpload: PersistenceGetSignedUrlForUpload = async ({

const command = new PutObjectCommand({
ACL: "public-read",
Bucket: process.env.S3_BUCKET_NAME,
Key: filename,
Bucket,
Key,
StorageClass: "INTELLIGENT_TIERING",
});

Expand Down
6 changes: 4 additions & 2 deletions process.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ declare namespace NodeJS {
AZURE_AD_CLIENT_SECRET: string;
AZURE_AD_CLIENT_ID: string;
AZURE_AD_TENANT_ID: string;
S3_UPLOADS_BUCKET: string;
S3_BUCKET_JCT: string;
S3_BUCKET_HEARINGS: string;
S3_ACCESS_KEY: string;
S3_SECRET_KEY: string;
NEXT_PUBLIC_S3_URL_PREFIX: string;
NEXT_PUBLIC_S3_HEARINGS_URL_PREFIX: string;
NEXT_PUBLIC_S3_JCT_URL_PREFIX: string;
}
}
1 change: 1 addition & 0 deletions types/DocType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type DocType = "JCT" | "Hearing";
15 changes: 15 additions & 0 deletions upload-bucket-cors-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT"
],
"AllowedOrigins": [
"<DOMAIN_NAME>"
],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
19 changes: 19 additions & 0 deletions upload-bucket-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<ACCOUNT_ID>:root"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::<BUCKET_NAME>/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<BUCKET_NAME>/*"
}
]
}

0 comments on commit e88272f

Please sign in to comment.