From 8d445d30400c9ad8ec293c83803a06c669a7cc43 Mon Sep 17 00:00:00 2001 From: Wieland Date: Mon, 2 Feb 2026 20:23:11 -0800 Subject: [PATCH] feat: add resource type to uploads --- frontend/app/api/upload/route.ts | 17 ++++++++- frontend/app/upload/page.tsx | 37 +++++++++++++++++++ ...3090000_add_resource_type_to_resources.sql | 15 ++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 supabase/migrations/202503090000_add_resource_type_to_resources.sql diff --git a/frontend/app/api/upload/route.ts b/frontend/app/api/upload/route.ts index b07c2f6..b92a759 100644 --- a/frontend/app/api/upload/route.ts +++ b/frontend/app/api/upload/route.ts @@ -5,6 +5,12 @@ import { createClient } from "@supabase/supabase-js"; const MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024; const PDF_MIME_TYPES = new Set(["application/pdf"]); const STORAGE_BUCKET = "resources"; +const RESOURCE_TYPES = new Set([ + "lecture_notes", + "study_guide", + "class_overview", + "link", +]); const isUuid = (value: string) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value); @@ -82,6 +88,7 @@ export async function POST(req: NextRequest) { const file = formData.get("file"); const classId = (formData.get("class_id") as string | null)?.trim(); const title = (formData.get("title") as string | null)?.trim(); + const resourceType = (formData.get("resource_type") as string | null)?.trim(); if (!(file instanceof File)) { return NextResponse.json({ error: "A PDF file is required." }, { status: 400 }); @@ -98,6 +105,13 @@ export async function POST(req: NextRequest) { ); } + if (!resourceType || !RESOURCE_TYPES.has(resourceType)) { + return NextResponse.json( + { error: "resource_type must be a valid value." }, + { status: 400 }, + ); + } + if (file.size === 0 || file.size > MAX_FILE_SIZE_BYTES) { return NextResponse.json( { error: `PDF must be between 1 byte and ${MAX_FILE_SIZE_BYTES} bytes.` }, @@ -156,6 +170,7 @@ export async function POST(req: NextRequest) { profile_id: userId, course_id: classId, title, + resource_type: resourceType, file_key: filePath, preview_key: filePath, }) @@ -202,4 +217,4 @@ export async function POST(req: NextRequest) { } return NextResponse.json({ data: resource }, { status: 200 }); -} \ No newline at end of file +} diff --git a/frontend/app/upload/page.tsx b/frontend/app/upload/page.tsx index 0d2b921..1c0df08 100644 --- a/frontend/app/upload/page.tsx +++ b/frontend/app/upload/page.tsx @@ -38,6 +38,13 @@ const emptyCourseRequest: CourseRequestForm = { justification: "", }; +const resourceTypeOptions = [ + { label: "Lecture Notes", value: "lecture_notes" }, + { label: "Study Guide", value: "study_guide" }, + { label: "Class Overview", value: "class_overview" }, + { label: "Link", value: "link" }, +] as const; + export default function UploadPage() { const [classes, setClasses] = useState([]); const [classSearch, setClassSearch] = useState(""); @@ -56,6 +63,7 @@ export default function UploadPage() { const [numPages, setNumPages] = useState(null); const [pageNumber, setPageNumber] = useState(1); const [title, setTitle] = useState(""); + const [resourceType, setResourceType] = useState(""); const [accessToken, setAccessToken] = useState(null); const [result, setResult] = useState(null); const [submitError, setSubmitError] = useState(null); @@ -288,6 +296,12 @@ export default function UploadPage() { return; } + if (!resourceType) { + setSubmitError("Please select a resource type."); + setIsUploading(false); + return; + } + if (!accessToken) { setSubmitError("Missing access token. Please re-authenticate."); setIsUploading(false); @@ -298,6 +312,7 @@ export default function UploadPage() { formData.append("file", file); formData.append("class_id", classId); formData.append("title", title); + formData.append("resource_type", resourceType); try { const res = await fetch("/api/upload", { @@ -535,6 +550,28 @@ export default function UploadPage() { /> +
+ + +
+ {/* remove in production, kept for testing purposes */} {/*
diff --git a/supabase/migrations/202503090000_add_resource_type_to_resources.sql b/supabase/migrations/202503090000_add_resource_type_to_resources.sql new file mode 100644 index 0000000..9e3301a --- /dev/null +++ b/supabase/migrations/202503090000_add_resource_type_to_resources.sql @@ -0,0 +1,15 @@ +alter table public.resources + add column if not exists resource_type text; + +do $$ +begin + if not exists ( + select 1 + from pg_constraint + where conname = 'check_resource_type' + ) then + alter table public.resources + add constraint check_resource_type + check (resource_type in ('lecture_notes', 'study_guide', 'class_overview', 'link')); + end if; +end $$;