Fixed warehouse api auth and extended artefact type
This commit is contained in:
parent
3b2927e896
commit
8341d9d8ce
8
package-lock.json
generated
8
package-lock.json
generated
@ -35,7 +35,7 @@
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-node": "^1.0.2",
|
||||
"swr": "^2.3.3",
|
||||
"zod": "^3.24.4"
|
||||
"zod": "^3.25.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
@ -8095,9 +8095,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.0",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.0.tgz",
|
||||
"integrity": "sha512-ficnZKUW0mlNivqeJkosTEkGbJ6NKCtSaOHGx5aXbtfeWMdRyzXLbAIn19my4C/KB7WPY/p9vlGPt+qpOp6c4Q==",
|
||||
"version": "3.25.3",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.3.tgz",
|
||||
"integrity": "sha512-VGZqnyYNrl8JpEJRZaFPqeVNIuqgXNu4cXZ5cOb6zEUO1OxKbRnWB4UdDIXMmiERWncs0yDQukssHov8JUxykQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-node": "^1.0.2",
|
||||
"swr": "^2.3.3",
|
||||
"zod": "^3.24.4"
|
||||
"zod": "^3.25.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
|
||||
@ -11,10 +11,7 @@ export async function POST(req: Request) {
|
||||
try {
|
||||
cookieStore = await cookies();
|
||||
const token = cookieStore.get("jwt")?.value;
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json({ error: "No JWT found" }, { status: 401 });
|
||||
}
|
||||
if (!token) return NextResponse.json({ error: "No JWT found" }, { status: 401 });
|
||||
|
||||
const payload = await verifyJwt({ token, secret: env.JWT_SECRET_KEY });
|
||||
|
||||
|
||||
@ -1,105 +1,46 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { JWTPayload } from "@appTypes/JWT";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
import { PrismaClient } from "@prismaclient";
|
||||
import { env } from "@utils/env";
|
||||
import { verifyJwt } from "@utils/verifyJwt";
|
||||
import { ExtendedArtefact } from "@appTypes/ApiTypes";
|
||||
import { apiAuthMiddleware } from "@utils/apiAuthMiddleware";
|
||||
|
||||
const usingPrisma = false;
|
||||
let prisma: PrismaClient;
|
||||
if (usingPrisma) prisma = new PrismaClient();
|
||||
|
||||
// Artefact type
|
||||
interface Artefact {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
location: string;
|
||||
earthquakeId: string;
|
||||
isRequired: boolean;
|
||||
isSold: boolean;
|
||||
isCollected: boolean;
|
||||
dateAdded: string;
|
||||
}
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
// todo fix, moron the token will be in the cookie header
|
||||
const json = await req.json(); // Parse incoming JSON data
|
||||
const { token } = json.body;
|
||||
if (!token) return NextResponse.json({ message: "Unauthorised" }, { status: 401 });
|
||||
await verifyJwt({ token, secret: env.JWT_SECRET_KEY });
|
||||
const authResult = await apiAuthMiddleware();
|
||||
if ("user" in authResult === false) return authResult; // Handle error response
|
||||
|
||||
const warehouseArtefacts: Artefact[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Solidified Lava Chunk",
|
||||
description: "A chunk of solidified lava from the 2023 Iceland eruption.",
|
||||
location: "Reykjanes, Iceland",
|
||||
earthquakeId: "EQ2023ICL",
|
||||
isRequired: true,
|
||||
isSold: false,
|
||||
isCollected: false,
|
||||
dateAdded: "2025-05-04",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Tephra Sample",
|
||||
description: "Foreign debris from the 2022 Tonga volcanic eruption.",
|
||||
location: "Tonga",
|
||||
earthquakeId: "EQ2022TGA",
|
||||
isRequired: false,
|
||||
isSold: true,
|
||||
isCollected: true,
|
||||
dateAdded: "2025-05-03",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Ash Sample",
|
||||
description: "Volcanic ash from the 2021 La Palma eruption.",
|
||||
location: "La Palma, Spain",
|
||||
earthquakeId: "EQ2021LPA",
|
||||
isRequired: false,
|
||||
isSold: false,
|
||||
isCollected: false,
|
||||
dateAdded: "2025-05-04",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Ground Soil",
|
||||
description: "Soil sample from the 2020 Croatia earthquake site.",
|
||||
location: "Zagreb, Croatia",
|
||||
earthquakeId: "EQ2020CRO",
|
||||
isRequired: true,
|
||||
isSold: false,
|
||||
isCollected: false,
|
||||
dateAdded: "2025-05-02",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Basalt Fragment",
|
||||
description: "Basalt rock from the 2019 New Zealand eruption.",
|
||||
location: "White Island, New Zealand",
|
||||
earthquakeId: "EQ2019NZL",
|
||||
isRequired: false,
|
||||
isSold: true,
|
||||
isCollected: false,
|
||||
dateAdded: "2025-05-04",
|
||||
},
|
||||
];
|
||||
const { user } = authResult;
|
||||
|
||||
let artefacts;
|
||||
if (usingPrisma) artefacts = await prisma.artefact.findMany();
|
||||
if (user.role !== "SCIENTIST" && user.role !== "ADMIN") {
|
||||
return NextResponse.json({ message: "Not authorised" }, { status: 401 });
|
||||
}
|
||||
|
||||
const artefacts = await prisma.artefact.findMany({
|
||||
include: {
|
||||
earthquake: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (artefacts) {
|
||||
return NextResponse.json({ message: "Got artefacts successfully", artefacts }, { status: 200 });
|
||||
const extendedArtefacts: ExtendedArtefact[] = artefacts.map((x) => ({
|
||||
...x,
|
||||
location: x.earthquake.location,
|
||||
date: x.earthquake.date,
|
||||
}));
|
||||
return NextResponse.json({ message: "Got artefacts successfully", artefacts: extendedArtefacts }, { status: 200 });
|
||||
} else {
|
||||
return NextResponse.json({ message: "Got earthquakes successfully", earthquakes: warehouseArtefacts }, { status: 200 });
|
||||
// return NextResponse.json({ message: "Failed to get earthquakes" }, { status: 401 });
|
||||
return NextResponse.json({ message: "Failed to get earthquakes" }, { status: 401 });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in artefacts endpoint:", error);
|
||||
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
|
||||
} finally {
|
||||
if (usingPrisma) await prisma.$disconnect();
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,12 +2,11 @@
|
||||
import Image from "next/image";
|
||||
import { Dispatch, SetStateAction, useCallback, useState } from "react";
|
||||
|
||||
import Artefact from "@appTypes/Artefact";
|
||||
import { ExtendedArtefact } from "@appTypes/ApiTypes";
|
||||
import { Currency } from "@appTypes/StoreModel";
|
||||
import { useStoreState } from "@hooks/store";
|
||||
|
||||
// Artefacts Data
|
||||
const artefacts: Artefact[] = [
|
||||
const artefacts: ExtendedArtefact[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Golden Scarab",
|
||||
|
||||
@ -3,17 +3,14 @@ import { Dispatch, SetStateAction, useMemo, useState } from "react";
|
||||
import { FaTimes } from "react-icons/fa";
|
||||
import { FaCalendarPlus, FaCartShopping, FaWarehouse } from "react-icons/fa6";
|
||||
import { IoFilter, IoFilterCircleOutline, IoFilterOutline, IoToday } from "react-icons/io5";
|
||||
import { ExtendedArtefact } from "@appTypes/ApiTypes";
|
||||
|
||||
// import { Artefact } from "@appTypes/Prisma";
|
||||
|
||||
import type { Artefact } from "@prismaclient";
|
||||
|
||||
interface WarehouseArtefact extends Artefact {
|
||||
location: string;
|
||||
}
|
||||
|
||||
// Warehouse Artefacts Data
|
||||
const warehouseArtefacts: WarehouseArtefact[] = [
|
||||
const extendedArtefacts: ExtendedArtefact[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Solidified Lava Chunk",
|
||||
@ -699,7 +696,7 @@ export default function Warehouse() {
|
||||
// Apply filters with loading state
|
||||
const filteredArtefacts = useMemo(() => {
|
||||
setIsFiltering(true);
|
||||
const result = applyFilters(warehouseArtefacts, filters);
|
||||
const result = applyFilters(extendedArtefacts, filters);
|
||||
setIsFiltering(false);
|
||||
return result;
|
||||
}, [filters]);
|
||||
@ -707,10 +704,10 @@ export default function Warehouse() {
|
||||
const currentArtefacts = filteredArtefacts.slice(indexOfFirstArtefact, indexOfLastArtefact);
|
||||
|
||||
// Overview stats
|
||||
const totalArtefacts = warehouseArtefacts.length;
|
||||
const totalArtefacts = extendedArtefacts.length;
|
||||
const today = new Date();
|
||||
const artefactsAddedToday = warehouseArtefacts.filter((a) => a.createdAt.toDateString() === today.toDateString()).length;
|
||||
const artefactsSoldToday = warehouseArtefacts.filter(
|
||||
const artefactsAddedToday = extendedArtefacts.filter((a) => a.createdAt.toDateString() === today.toDateString()).length;
|
||||
const artefactsSoldToday = extendedArtefacts.filter(
|
||||
(a) => a.isSold && a.createdAt.toDateString() === today.toDateString()
|
||||
).length;
|
||||
|
||||
@ -803,8 +800,11 @@ export default function Warehouse() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modals */}
|
||||
{/* // todo only admins and senior scientists can log, add not allowed modal for juniors */}
|
||||
{/* // todo add new artefact/pallet saving */}
|
||||
{/* // todo add existing artefact modifying */}
|
||||
{/* // todo add pallet display */}
|
||||
{showLogModal && <LogModal onClose={() => setShowLogModal(false)} />}
|
||||
{showBulkLogModal && <BulkLogModal onClose={() => setShowBulkLogModal(false)} />}
|
||||
{editArtefact && <EditModal artefact={editArtefact} onClose={() => setEditArtefact(null)} />}
|
||||
|
||||
@ -10,6 +10,7 @@ interface AuthModalProps {
|
||||
}
|
||||
|
||||
export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
// todo add login successful message
|
||||
const [isLogin, setIsLogin] = useState<boolean>(true);
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
const [isFailed, setIsFailed] = useState<boolean>(false);
|
||||
|
||||
8
src/types/ApiTypes.ts
Normal file
8
src/types/ApiTypes.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Artefact } from "@prismaclient";
|
||||
|
||||
interface ExtendedArtefact extends Artefact {
|
||||
location: string;
|
||||
date: Date;
|
||||
}
|
||||
|
||||
export type { ExtendedArtefact };
|
||||
@ -1,14 +0,0 @@
|
||||
interface Artefact {
|
||||
// todo change to string
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
location: string;
|
||||
earthquakeID: string;
|
||||
observatory: string;
|
||||
dateReleased: string;
|
||||
image: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
export default Artefact;
|
||||
5
src/types/JWT.ts
Normal file
5
src/types/JWT.ts
Normal file
@ -0,0 +1,5 @@
|
||||
interface JWTPayload {
|
||||
userId: number;
|
||||
}
|
||||
|
||||
export type { JWTPayload };
|
||||
33
src/utils/apiAuthMiddleware.ts
Normal file
33
src/utils/apiAuthMiddleware.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import { verifyJwt } from "@utils/verifyJwt";
|
||||
import { PrismaClient } from "@prismaclient";
|
||||
import type { JWTPayload } from "@/types/JWT";
|
||||
import { env } from "@utils/env";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export async function apiAuthMiddleware() {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get("jwt")?.value;
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json({ error: "No JWT found" }, { status: 401 });
|
||||
}
|
||||
|
||||
const payload = (await verifyJwt({
|
||||
token,
|
||||
secret: env.JWT_SECRET_KEY,
|
||||
})) as unknown as JWTPayload;
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: payload.userId },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
cookieStore.delete("jwt");
|
||||
return NextResponse.json({ error: "Failed to get user" }, { status: 401 });
|
||||
}
|
||||
|
||||
return { user, payload };
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user