diff --git a/src/app/api/update-user/route.ts b/src/app/api/update-user/route.ts index 1cc7721..c33c13b 100644 --- a/src/app/api/update-user/route.ts +++ b/src/app/api/update-user/route.ts @@ -29,7 +29,6 @@ export async function POST(req: Request) { // Trying to update a different user than themselves // Only available to admins - // todo add senior scientists being able to update their juniors if (userId && userId !== user.id) { if (user.role !== "ADMIN") { return NextResponse.json({ message: "Not authorised" }, { status: 401 }); diff --git a/src/app/api/warehouse/edit-artefact/route.ts b/src/app/api/warehouse/edit-artefact/route.ts new file mode 100644 index 0000000..54c78f7 --- /dev/null +++ b/src/app/api/warehouse/edit-artefact/route.ts @@ -0,0 +1,86 @@ +import { NextRequest, NextResponse } from "next/server"; +import { apiAuthMiddleware } from "@utils/apiAuthMiddleware"; +import { prisma } from "@utils/prisma"; +import { writeFile } from "fs/promises"; +import { join } from "path"; + +export async function POST(request: NextRequest) { + try { + const formData = await request.formData(); + const id = formData.get("id") as string; + const name = formData.get("name") as string | null; + const description = formData.get("description") as string | null; + const location = formData.get("location") as string | null; + const earthquakeCode = formData.get("earthquakeCode") as string | null; + const image = formData.get("image") as File | null; + + const authResult = await apiAuthMiddleware(); + if ("user" in authResult === false) return authResult; + + const { user } = authResult; + + if (!id) { + return NextResponse.json({ error: "Artefact ID required" }, { status: 400 }); + } + + const artefact = await prisma.artefact.findUnique({ + where: { id: parseInt(id) }, + }); + + if (!artefact) { + return NextResponse.json({ error: "Artefact not found" }, { status: 404 }); + } + + if (user.role !== "ADMIN" && user.role !== "SCIENTIST") { + return NextResponse.json({ error: "Not authorized" }, { status: 401 }); + } + + if (user.role === "SCIENTIST") { + const scientist = await prisma.scientist.findUnique({ + where: { + userId: user.id, + }, + include: { + subordinates: true, + }, + }); + + if (!scientist || scientist.level !== "SENIOR") { + return NextResponse.json({ message: "Not authorised" }, { status: 401 }); + } + } + + let earthquakeId = artefact.earthquakeId; + if (earthquakeCode) { + const linkedEarthquake = await prisma.earthquake.findUnique({ where: { code: earthquakeCode } }); + if (!linkedEarthquake) { + return NextResponse.json({ error: "Earthquake code not found" }, { status: 400 }); + } + earthquakeId = linkedEarthquake.id; + } + + let imageName = artefact.imageName; + if (image) { + const buffer = Buffer.from(await image.arrayBuffer()); + const extension = image.type === "image/jpeg" ? "jpg" : "png"; + imageName = `${name || artefact.name}-${new Date().toLocaleDateString("en-GB")}.${extension}`; + const imagePath = join(process.cwd(), "public", imageName); + await writeFile(imagePath, buffer); + } + + const updatedArtefact = await prisma.artefact.update({ + where: { id: parseInt(id) }, + data: { + name: name || artefact.name, + description: description || artefact.description, + warehouseArea: location || artefact.warehouseArea, + earthquakeId, + imageName, + }, + }); + + return NextResponse.json({ message: "Artefact updated successfully", artefact: updatedArtefact }, { status: 200 }); + } catch (e: any) { + return NextResponse.json({ error: e.message }, { status: 500 }); + } +} diff --git a/src/app/warehouse/page.tsx b/src/app/warehouse/page.tsx index c1f22ec..e92591e 100644 --- a/src/app/warehouse/page.tsx +++ b/src/app/warehouse/page.tsx @@ -77,198 +77,6 @@ function FilterInput({ ); } -function LogModal({ onClose }: { onClose: () => void }) { - const [name, setName] = useState(""); - const [type, setType] = useState(""); - const [description, setDescription] = useState(""); - const [location, setLocation] = useState(""); - const [earthquakeCode, setEarthquakeCode] = useState(""); - const [warehouseLocation, setWarehouseLocation] = useState(""); - const [isRequired, setIsRequired] = useState(true); - const [error, setError] = useState(""); - const [isSubmitting, setIsSubmitting] = useState(false); - const [image, setImage] = useState(null); - - const handleOverlayClick = (e: { target: any; currentTarget: any }) => { - if (e.target === e.currentTarget) { - onClose(); - } - }; - - const handleImageChange = (e: React.ChangeEvent) => { - if (e.target.files && e.target.files[0]) { - const file = e.target.files[0]; - if (file.size > 5 * 1024 * 1024) { - setError("Image size must be less than 5MB"); - return; - } - if (!["image/jpeg", "image/png"].includes(file.type)) { - setError("Only JPEG or PNG images are allowed"); - return; - } - setImage(file); - } - }; - - async function handleLog() { - if (!name || !type || !description || !location || !earthquakeCode || !warehouseLocation) { - setError("All fields are required."); - return; - } - if (!validateEarthquakeCode(earthquakeCode)) { - setError("Earthquake Code must be in format: EX-M.M-Country-##### (e.g., EC-3.9-Belgium-05467)"); - return; - } - setIsSubmitting(true); - try { - const formData = new FormData(); - formData.append("name", name); - formData.append("type", type); - formData.append("description", description); - formData.append("location", location); - formData.append("earthquakeCode", earthquakeCode); - formData.append("warehouseLocation", warehouseLocation); - if (image) { - formData.append("image", image); - } - - await axios.post("/api/warehouse/log", formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); - - alert(`Logged ${name} to storage: ${warehouseLocation}`); - onClose(); - } catch { - setError("Failed to log artefact. Please try again."); - } finally { - setIsSubmitting(false); - } - } - - return ( -
-
-

Log New Artefact

- {error &&

{error}

} -
- setName(e.target.value)} - className="w-full p-2 border border-neutral-300 rounded-md placeholder-neutral-400 focus:ring-2 focus:ring-blue-500" - aria-label="Artefact Name" - disabled={isSubmitting} - /> - setType(e.target.value)} - className="w-full p-2 border border-neutral-300 rounded-md placeholder-neutral-400 focus:ring-2 focus:ring-blue-500" - aria-label="Artefact Type" - disabled={isSubmitting} - /> -