Added update-user route and made a few small other changes

This commit is contained in:
Tim Howitz 2025-05-31 18:55:39 +01:00
parent 9c1c696352
commit 4c4e48fcd4
5 changed files with 103 additions and 13 deletions

View File

@ -5,17 +5,10 @@ import { NextResponse } from "next/server";
import { env } from "@utils/env"; import { env } from "@utils/env";
import { prisma } from "@utils/prisma"; import { prisma } from "@utils/prisma";
import { findUserByEmail, readUserCsv, User } from "../functions/csvReadWrite";
export async function POST(req: Request) { export async function POST(req: Request) {
try { try {
const { email, password } = await req.json(); // Parse incoming JSON data const { email, password } = await req.json(); // Parse incoming JSON data
const userData = await readUserCsv();
console.log(userData);
console.log("Email:", email); // ! remove
console.log("Password:", password); // ! remove
let user = await prisma.user.findUnique({ let user = await prisma.user.findUnique({
where: { where: {
email, // use the email to uniquely identify the user email, // use the email to uniquely identify the user

View File

@ -7,6 +7,8 @@ import { prisma } from "@utils/prisma";
import { passwordStrengthCheck } from "@utils/validation"; import { passwordStrengthCheck } from "@utils/validation";
// todo check email doesn't already exist
export async function POST(req: Request) { export async function POST(req: Request) {
try { try {
const { email, password, name } = await req.json(); const { email, password, name } = await req.json();

View File

@ -0,0 +1,97 @@
import { NextResponse } from "next/server";
import bcryptjs from "bcryptjs";
import { env } from "@utils/env";
import { prisma } from "@utils/prisma";
import { apiAuthMiddleware } from "@utils/apiAuthMiddleware";
import { passwordStrengthCheck } from "@utils/validation";
export async function POST(req: Request) {
try {
const authResult = await apiAuthMiddleware();
if ("user" in authResult === false) return authResult;
const { user } = authResult;
const { email, name, password } = await req.json();
// Check if email is already in use by another user
if (email && email !== user.email) {
const foundUser = await prisma.user.findUnique({
where: { email },
});
if (foundUser) {
return NextResponse.json({ message: "This email is already in use" }, { status: 409 });
}
}
// Validate password strength if provided
let passwordHash = user.passwordHash;
if (password) {
const passwordCheckResult = await passwordStrengthCheck(password);
if (passwordCheckResult === "short") {
return NextResponse.json({ message: "Password is shorter than 8 characters" }, { status: 400 });
} else if (passwordCheckResult === "long") {
return NextResponse.json({ message: "Password is longer than 16 characters" }, { status: 400 });
} else if (passwordCheckResult === "no lower") {
return NextResponse.json({ message: "Password must contain lowercase letters" }, { status: 400 });
} else if (passwordCheckResult === "no upper") {
return NextResponse.json({ message: "Password must contain uppercase letters" }, { status: 400 });
} else if (passwordCheckResult === "no digit") {
return NextResponse.json({ message: "Password must contain a number" }, { status: 400 });
} else if (passwordCheckResult === "no special") {
return NextResponse.json({ message: "Password must contain a special character (!@#$%^&*)" }, { status: 400 });
} else if (passwordCheckResult === "end of function") {
return NextResponse.json({ message: "Password check script failure" }, { status: 500 });
}
passwordHash = await bcryptjs.hash(password, 10);
}
// Update user in database
const updatedUser = await prisma.user.update({
where: { id: user.id },
data: {
name: name || user.name,
email: email || user.email,
passwordHash,
},
});
// Link orders with matching email to the updated user
if (email && email !== user.email) {
await prisma.order.updateMany({
where: {
email,
userId: null,
},
data: {
userId: updatedUser.id,
},
});
}
const fullUser = await prisma.user.findUnique({
where: { id: updatedUser.id },
include: {
earthquakes: true,
observatories: true,
artefacts: true,
purchasedOrders: true,
requests: true,
scientist: {
include: {
superior: true,
subordinates: true,
},
},
},
});
const { passwordHash: _, ...userSansHash } = fullUser!;
return NextResponse.json({ message: "User updated successfully", user: userSansHash }, { status: 200 });
} catch (error) {
console.error("Error in update-user endpoint:", error);
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
}
}

View File

@ -34,8 +34,6 @@ const store = createStore<StoreModel>({
}), }),
}); });
// todo fix user persisting on reload
function UserFetcher() { function UserFetcher() {
const setUser = useStoreActions((actions) => actions.setUser); const setUser = useStoreActions((actions) => actions.setUser);
const { data, error } = useSWR("/api/user", fetcher); const { data, error } = useSWR("/api/user", fetcher);

View File

@ -23,13 +23,13 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
if (!isOpen) return null; // if is open is false, the model isnt shown if (!isOpen) return null; // if is open is false, the model isnt shown
const handleOverlayClick = (e: MouseEvent<HTMLDivElement>) => { function handleOverlayClick(e: MouseEvent<HTMLDivElement>) {
if (modalRef.current && !modalRef.current.contains(e.target as Node)) { if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
onClose(); onClose();
} }
}; }
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { async function handleSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault(); e.preventDefault();
setIsFailed(false); setIsFailed(false);
@ -74,7 +74,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
setIsFailed(true); setIsFailed(true);
} }
} }
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50" onClick={handleOverlayClick}> <div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50" onClick={handleOverlayClick}>