diff --git a/calc-backend/src/controllers/func.controller.ts b/calc-backend/src/controllers/func.controller.ts index 0e27fce..5c2f29d 100644 --- a/calc-backend/src/controllers/func.controller.ts +++ b/calc-backend/src/controllers/func.controller.ts @@ -4,11 +4,16 @@ import { IntegralData } from "../types"; // will need middleware to check if func is valid and unique to specific topic export async function createIntegral(req: Request, res: Response) -{ +{ const { equation, lowerBound, upperBound, topic }: IntegralData = req.body; - const userId = req.params.id; + const userId = req.user.id; try { + const funcCount = await prisma.func.count({ where: { userId } }); + if (funcCount >= 30) { + return res.status(400).json({ message: "You can only save up to 30 functions" }); + } + const newFunc = await prisma.func.create({ data: { equation, @@ -26,11 +31,8 @@ export async function createIntegral(req: Request, res: Response) export async function getUserFuncs(req: Request, res: Response) { - const userId = req.params.id; - if(!userId) { - return res.status(404).json({message: "Function ID is required"}) - } - + const userId = req.user.id; + try { const funcs = await prisma.func.findMany({ where: {userId}, @@ -44,14 +46,20 @@ export async function getUserFuncs(req: Request, res: Response) export async function deleteUserFunc(req: Request, res: Response) { const functionId = req.params.id; + const userId = req.user.id; try { - const deletedFunc = await prisma.func.delete({ - where: { - id: functionId, - }, - }) - res.status(200).json({message: "Function deleted!"}) + const func = await prisma.func.findUnique({ where: { id: functionId } }); + + if (!func) { + return res.status(404).json({ message: "Function not found" }); + } + if (func.userId !== userId) { + return res.status(403).json({ message: "Forbidden" }); + } + + await prisma.func.delete({ where: { id: functionId } }); + res.status(200).json({ message: "Function deleted!" }) } catch (err) { res.status(500).json({message: "Failed to delete function", error: err}) } diff --git a/calc-backend/src/index.ts b/calc-backend/src/index.ts index 548d354..a6bae7b 100644 --- a/calc-backend/src/index.ts +++ b/calc-backend/src/index.ts @@ -1,7 +1,6 @@ import express from "express"; import cors from "cors"; import routes from "./server.routes"; -import errorMiddleware from "./middlewares/errorHandler.middleware"; import { toNodeHandler } from "better-auth/node"; import { auth } from "./lib/auth"; @@ -23,8 +22,6 @@ app.use(express.json()) // use this after better auth // Prefixes the endpoint with / app.use('/',routes); -//app.use(errorMiddleware); - app.listen(PORT, () => { console.log(`Server is running at http://localhost:${PORT}`); }); \ No newline at end of file diff --git a/calc-backend/src/middlewares/errorHandler.middleware.ts b/calc-backend/src/middlewares/errorHandler.middleware.ts deleted file mode 100644 index b1779b8..0000000 --- a/calc-backend/src/middlewares/errorHandler.middleware.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Here would go middleware that handles error checking - -import { NextFunction, Request, Response } from "express"; - -// at the end of every function in here should be a function call of next() -// this lets the middleware pass to the next piece of logic after its done - -const errorMiddleware = (err: Error, req: Request, res: Response, next: NextFunction) => { - try { - let error = {...err}; - - error.message = err.message; - console.error("middleware error: " + err); - - // check for specific error types - // set error message, maybe error code and throw the new error - - - } catch(error) { - next(error); - } - -}; - -export default errorMiddleware \ No newline at end of file diff --git a/calc-backend/src/middlewares/requireAuth.middleware.ts b/calc-backend/src/middlewares/requireAuth.middleware.ts new file mode 100644 index 0000000..ad0ea68 --- /dev/null +++ b/calc-backend/src/middlewares/requireAuth.middleware.ts @@ -0,0 +1,14 @@ +import { Request, Response, NextFunction } from "express"; +import { auth } from "../lib/auth"; +import { fromNodeHeaders } from "better-auth/node"; + +export async function requireAuth(req: Request, res: Response, next: NextFunction) { + const session = await auth.api.getSession({ + headers: fromNodeHeaders(req.headers), + }); + if (!session) { + return res.status(401).json({ message: "Unauthorized" }); + } + req.user = session.user; + next(); +} diff --git a/calc-backend/src/routes/func.routes.ts b/calc-backend/src/routes/func.routes.ts index 59edec1..2a85386 100644 --- a/calc-backend/src/routes/func.routes.ts +++ b/calc-backend/src/routes/func.routes.ts @@ -1,10 +1,12 @@ import { Router } from "express"; import { createIntegral, deleteUserFunc, getUserFuncs } from "../controllers/func.controller"; +import { requireAuth } from "../middlewares/requireAuth.middleware"; const router = Router(); -router.post("/create-integral/:id", createIntegral); -router.get("/all/:id", getUserFuncs); -router.delete("/delete/:id", deleteUserFunc); +// These routes can only be accessed by authenticated users +router.post("/create-integral", requireAuth, createIntegral); +router.get("/all", requireAuth, getUserFuncs); +router.delete("/delete/:id", requireAuth, deleteUserFunc); export default router; \ No newline at end of file diff --git a/calc-backend/src/types.ts b/calc-backend/src/types.ts index 48366ce..9948b51 100644 --- a/calc-backend/src/types.ts +++ b/calc-backend/src/types.ts @@ -1,3 +1,16 @@ +declare global { + namespace Express { + interface Request { + user: { + id: string; + name: string; + email: string; + [key: string]: any; + }; + } + } +} + export interface IntegralData { equation: string; lowerBound: number; diff --git a/calc-frontend/src/components/Custom/LimCustomGraph.tsx b/calc-frontend/src/components/Custom/LimCustomGraph.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/calc-frontend/src/components/ui/SaveFunctionButton.tsx b/calc-frontend/src/components/ui/SaveFunctionButton.tsx index a8be2a2..6bbd099 100644 --- a/calc-frontend/src/components/ui/SaveFunctionButton.tsx +++ b/calc-frontend/src/components/ui/SaveFunctionButton.tsx @@ -1,10 +1,9 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TooltipArrow } from "@radix-ui/react-tooltip"; -import { Session } from "../../lib/auth-client"; import { AuthContext } from "../../App/AuthProvider"; import { useContext } from "react"; import { useNavigate } from "react-router"; -function SaveFunctionButton({onSave, saving, enableSave}: {onSave: (session: Session) => void, +function SaveFunctionButton({onSave, saving, enableSave}: {onSave: () => void, saving: boolean, enableSave: boolean}) { const {session} = useContext(AuthContext); @@ -16,7 +15,7 @@ function SaveFunctionButton({onSave, saving, enableSave}: {onSave: (session: Ses navigate("/sign-in"); return; } - onSave(session); + onSave(); } if(saving){ diff --git a/calc-frontend/src/pages/CustomDerivative.tsx b/calc-frontend/src/pages/CustomDerivative.tsx index 1ed4468..4027ee4 100644 --- a/calc-frontend/src/pages/CustomDerivative.tsx +++ b/calc-frontend/src/pages/CustomDerivative.tsx @@ -8,7 +8,6 @@ import SaveFunctionButton from "../components/ui/SaveFunctionButton.tsx"; import AskAIButtonDerivative from "@/components/ui/AskAIButtonDerivative.tsx"; import { toast } from "sonner"; -import { Session } from "../lib/auth-client"; function CustomDeriv() { @@ -56,7 +55,7 @@ function CustomDeriv() { } // need to check if func is unique first - const saveFunction = async (session: Session) => { + const saveFunction = async () => { // check if function has been graphed if(func === ''){ @@ -69,13 +68,11 @@ function CustomDeriv() { const lowerBound = bounds[0]; const upperBound = bounds[1]; const topic = "Derivative"; - const userId = session?.user.id || ""; - try { setSaving(true) // show loading while saving // create-integral handles any topic - await axios.post(serverUrl + `/func/create-integral/${userId}`, { + await axios.post(serverUrl + `/func/create-integral`, { equation, lowerBound, upperBound, @@ -85,9 +82,13 @@ function CustomDeriv() { ) toast.success("Function Saved Successfully!"); - } + } catch (error) { - toast.error("Function Failed to Save"); + if (axios.isAxiosError(error) && error.response?.data?.message === "You can only save up to 30 functions") { + toast.error("You can only save up to 30 functions"); + } else { + toast.error("Function Failed to Save"); + } console.error("save function error: ",error); } finally{ diff --git a/calc-frontend/src/pages/CustomIntegral.tsx b/calc-frontend/src/pages/CustomIntegral.tsx index 1f1638e..9065cc7 100644 --- a/calc-frontend/src/pages/CustomIntegral.tsx +++ b/calc-frontend/src/pages/CustomIntegral.tsx @@ -8,7 +8,6 @@ import SaveFunctionButton from "../components/ui/SaveFunctionButton.tsx"; import AskAIButton from "../components/ui/AskAIButtonIntegral.tsx"; import { toast } from "sonner"; -import { Session } from "../lib/auth-client"; function CustomInt() { @@ -57,7 +56,7 @@ function CustomInt() { } // need to check if func is unique first - const saveFunction = async (session: Session) => { + const saveFunction = async () => { // check if function has been graphed if(func === ''){ @@ -70,12 +69,10 @@ function CustomInt() { const lowerBound = bounds[0]; const upperBound = bounds[1]; const topic = "Integral"; - const userId = session?.user.id || ""; - try { setSaving(true) // show loading while saving - await axios.post(serverUrl + `/func/create-integral/${userId}`, { + await axios.post(serverUrl + `/func/create-integral`, { equation, lowerBound, upperBound, @@ -85,9 +82,13 @@ function CustomInt() { ) toast.success("Function Saved Successfully!"); - } + } catch (error) { - toast.error("Function Failed to Save"); + if (axios.isAxiosError(error) && error.response?.data?.message === "You can only save up to 30 functions") { + toast.error("You can only save up to 30 functions"); + } else { + toast.error("Function Failed to Save"); + } console.error("save function error: ",error); } finally{ diff --git a/calc-frontend/src/pages/CustomLimit.tsx b/calc-frontend/src/pages/CustomLimit.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/calc-frontend/src/pages/Dashboard.tsx b/calc-frontend/src/pages/Dashboard.tsx index a98250d..037f42a 100644 --- a/calc-frontend/src/pages/Dashboard.tsx +++ b/calc-frontend/src/pages/Dashboard.tsx @@ -46,9 +46,8 @@ function Dashboard() } const getFuncs = async () => { - const userId = session.user.id; try { - const response = await axios.get(serverUrl + `/func/all/${userId}`); + const response = await axios.get(serverUrl + `/func/all`, { withCredentials: true }); setUserFunctions(response.data); } catch (error) { console.error("get function error: ", error);