Skip to content

Commit 9fedf73

Browse files
committed
feat: added new endpoints to save workout exercise and exercise enum
1 parent 3b945b5 commit 9fedf73

15 files changed

+242
-16
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"server"
1010
],
1111
"scripts": {
12-
"dev:server": "npm --workspace server run dev"
12+
"dev:server": "npm --workspace server run dev",
13+
"dev:server:prisma-studio": "npm --workspace server run prisma-studio"
1314
},
1415
"keywords": [],
1516
"author": "",

server/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "",
55
"main": "index.js",
66
"scripts": {
7-
"dev": "ts-node-dev --respawn --transpile-only --env-file .env src/index.ts"
7+
"dev": "ts-node-dev --respawn --transpile-only --env-file .env src/index.ts",
8+
"prisma-studio": "npx prisma studio"
89
},
910
"keywords": [],
1011
"author": "",
@@ -32,4 +33,4 @@
3233
"ts-node-dev": "^2.0.0",
3334
"typescript": "^5.8.3"
3435
}
35-
}
36+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import z from "zod"
2+
3+
export const fullExerciseEnumSchema = z.object({
4+
idExercise: z.number().int().optional(),
5+
idUser: z.number().int("MISSING_IDUSER"),
6+
exerciseName: z.string("MISSING_EXERCISENAME"),
7+
muscle: z.string("MISSING_MUSCLE"),
8+
description: z.string("MISSING_DESCRIPTION"),
9+
})
10+
11+
export type ExerciseEnumDTO = z.infer<typeof fullExerciseEnumSchema>
12+
export type CreateExerciseEnumDTO = Omit<ExerciseEnumDTO, "idExercise">
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import z from "zod"
2+
3+
export const fullWorkoutExerciseSchema = z.object({
4+
idWorkoutExercise: z.number().int().optional(),
5+
idWorkout: z.number().int("MISSING_IDWORKOUT"),
6+
idExercise: z.number().int("MISSING_IDEXERCISE")
7+
})
8+
9+
export type WorkoutExerciseDTO = z.infer<typeof fullWorkoutExerciseSchema>
10+
export type CreateWorkoutExerciseDTO = Omit<WorkoutExerciseDTO, "idWorkoutExercise">

server/src/http/server.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,27 @@ import cors from "cors"
33
import { errorHandler } from '../middleware/errorHandler'
44
import UserRoutes from '../routes/UserRoutes'
55
import WorkoutRoutes from "../routes/WorkoutRoutes"
6+
import ExerciseEnumRoutes from "../routes/ExerciseEnumRoutes"
7+
import WorkoutExerciseRoutes from "../routes/WorkoutExerciseRoutes"
68
import cookieParser from "cookie-parser"
9+
import { unauthenticatedMiddleware } from '../middleware/unauthenticated'
10+
import { Redis } from '../../utils/redis'
11+
import { JWTClass } from '../../utils/jwt'
712

813

914
const app = express()
15+
const redis = new Redis()
16+
const jwt = new JWTClass(process.env.JWT_TOKEN!)
1017

1118
app.use(cors())
1219
app.use(express.json())
1320
app.use(cookieParser())
1421

1522
app.use(UserRoutes)
16-
app.use(WorkoutRoutes)
23+
app.use(unauthenticatedMiddleware(jwt, redis), WorkoutRoutes)
24+
app.use(unauthenticatedMiddleware(jwt, redis), ExerciseEnumRoutes)
25+
app.use(unauthenticatedMiddleware(jwt, redis), WorkoutExerciseRoutes)
26+
1727

1828
app.use(errorHandler)
1929

server/src/middleware/errorHandler.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Request, Response, NextFunction } from "express";
22
import { HttpError } from "../errors/HttpError";
3+
import { PrismaClientKnownRequestError } from "../generated/prisma/runtime/library";
34

45

56
export function errorHandler(err: unknown, req: Request, res: Response, next: NextFunction) {
@@ -9,7 +10,13 @@ export function errorHandler(err: unknown, req: Request, res: Response, next: Ne
910
code: err.errorCode
1011
})
1112
}
13+
if (err instanceof PrismaClientKnownRequestError) {
14+
return res.status(500).json({
15+
error: "Error while trying to create resource!",
16+
code: "P_ERROR"
17+
})
18+
}
1219

13-
console.error("Unexpected error. " + err)
20+
console.log("Unexpected error. " + err)
1421
return res.status(500).json({ error: "Server error.", code: (err as string).toString() })
1522
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { NextFunction, Request, Response } from "express";
2+
import { CustomError } from "../errors/HttpError";
3+
import { JWTClass } from "../../utils/jwt";
4+
import { Redis } from "../../utils/redis";
5+
6+
7+
export function unauthenticatedMiddleware(jwt: JWTClass, redis: Redis) {
8+
return async (req: Request, res: Response, next: NextFunction) => {
9+
try {
10+
const token = req.cookies.token
11+
if (!token) return next(new CustomError("Unauthenticated.", 401, "UNAUTHENTICATED"))
12+
13+
const decoded = jwt.verifyJWT(token)
14+
if (!decoded?.email) return next(new CustomError("Unauthenticated.", 401, "UNAUTHENTICATED"))
15+
16+
const user = await redis.getRedis(decoded.email)
17+
if (!user) return next(new CustomError("Unauthenticated.", 401, "UNAUTHENTICATED"))
18+
19+
next()
20+
} catch (err) {
21+
next(err)
22+
}
23+
}
24+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import prisma from "../db/connect";
2+
import { CreateExerciseEnumDTO, ExerciseEnumDTO } from "../db/models/ExerciseEnumModel";
3+
4+
5+
export class ExerciseEnumRepository {
6+
async create(exercise: CreateExerciseEnumDTO): Promise<ExerciseEnumDTO> {
7+
return await prisma.exercisesEnum.create({
8+
data: exercise
9+
})
10+
}
11+
12+
async getExercisesEnum(idUser: number): Promise<ExerciseEnumDTO[]> {
13+
return await prisma.exercisesEnum.findMany({
14+
where: {
15+
idUser: idUser
16+
}
17+
})
18+
}
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import prisma from "../db/connect";
2+
import { CreateWorkoutExerciseDTO, WorkoutExerciseDTO } from "../db/models/WorkoutExerciseModel";
3+
4+
5+
export class WorkoutExerciseRepository {
6+
async create(workoutExercise: CreateWorkoutExerciseDTO): Promise<WorkoutExerciseDTO> {
7+
return await prisma.workoutExercises.create({
8+
data: workoutExercise,
9+
})
10+
}
11+
12+
async getUserWorkout(idUser: number, idWorkout: number): Promise<boolean> {
13+
const workout = await prisma.workouts.findFirst({
14+
where: {
15+
idWorkout,
16+
idUser
17+
}
18+
})
19+
20+
return !!workout
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import express, { Response, Request } from "express"
2+
import { ExerciseEnumService } from "../services/ExerciseEnumService"
3+
import { ExerciseEnumRepository } from "../repositories/ExerciseEnumRepository"
4+
import { JWTClass } from "../../utils/jwt"
5+
import { Redis } from "../../utils/redis"
6+
7+
const router = express.Router()
8+
const service = new ExerciseEnumService(new ExerciseEnumRepository(), new JWTClass(process.env.JWT_TOKEN!), new Redis())
9+
10+
router.post("/exercise/enum", async (req: Request, res: Response) => {
11+
const { exerciseName, muscle, description } = req.body
12+
const token = req.cookies.token
13+
14+
const newExerciseEnum = await service.createExerciseEnum({ exerciseName, muscle, description }, token)
15+
16+
return res.status(201).json({
17+
message: "Exercise enum created successfully!",
18+
code: "ENUM_CREATED",
19+
data: newExerciseEnum
20+
})
21+
})
22+
23+
router.get("/exercise/enum", async (req: Request, res: Response) => {
24+
const token = req.cookies.token
25+
26+
const exerciseEnum = await service.getExerciseEnum(token)
27+
28+
return res.status(201).json({
29+
message: "Exercise enum found.",
30+
code: "ENUM_SUCCESS",
31+
data: exerciseEnum
32+
})
33+
})
34+
35+
export default router

0 commit comments

Comments
 (0)