Skip to content

Commit

Permalink
Bugfix/issue 138 request validation (#146)
Browse files Browse the repository at this point in the history
Co-authored-by: Dileepa Mabulage <[email protected]>
  • Loading branch information
dsmabulage and dileepainivossl authored Aug 7, 2024
1 parent 7a7aae3 commit 135dce9
Show file tree
Hide file tree
Showing 19 changed files with 297 additions and 33 deletions.
11 changes: 10 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"pg": "^8.10.0",
"reflect-metadata": "^0.1.13",
"ts-node": "^10.9.1",
"typeorm": "^0.3.16"
"typeorm": "^0.3.16",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
Expand Down
41 changes: 41 additions & 0 deletions src/middlewares/requestValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { type NextFunction, type Request, type Response } from 'express'
import { ZodError, type ZodSchema } from 'zod'

export const requestBodyValidator = <T extends ZodSchema>(schema: T) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
schema.parse(req.body)
next()
} catch (err) {
console.log(err)
if (err instanceof ZodError) {
const errorMessages = err.errors.map((issue) => ({
message: `${issue.path.join('.')} is ${issue.message}`
}))
return res
.status(400)
.json({ error: 'Invalid data', details: errorMessages })
}
return res.status(500).json({ error: 'Internal server error' })
}
}
}

export const requestQueryValidator = <T extends ZodSchema>(schema: T) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
schema.parse(req.query)
next()
} catch (err) {
if (err instanceof ZodError) {
const errorMessages = err.errors.map((issue) => ({
message: `${issue.path.join('.')} is ${issue.message}`
}))
return res
.status(400)
.json({ error: 'Invalid data', details: errorMessages })
}
return res.status(500).json({ error: 'Internal server error' })
}
}
}
19 changes: 16 additions & 3 deletions src/routes/admin/category/category.route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import express from 'express'
import { requireAuth } from '../../../controllers/auth.controller'
import {
addCategory,
updateCategory
} from '../../../controllers/admin/category.controller'
import { requireAuth } from '../../../controllers/auth.controller'
import { requestBodyValidator } from '../../../middlewares/requestValidator'
import {
addCategorySchema,
updateCategorySchema
} from '../../../schemas/admin/admin.category-routes.schema'

const categoryRouter = express.Router()

categoryRouter.post('/', requireAuth, addCategory)
categoryRouter.put('/:categoryId', requireAuth, updateCategory)
categoryRouter.post(
'/',
[requireAuth, requestBodyValidator(addCategorySchema)],
addCategory
)
categoryRouter.put(
'/:categoryId',
[requireAuth, requestBodyValidator(updateCategorySchema)],
updateCategory
)

export default categoryRouter
35 changes: 28 additions & 7 deletions src/routes/admin/mentee/mentee.route.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
import express from 'express'
import { requireAuth } from '../../../controllers/auth.controller'
import {
getMentees,
updateMenteeStatus,
getAllMenteeEmails,
getMenteeDetails
getMenteeDetails,
getMentees,
updateMenteeStatus
} from '../../../controllers/admin/mentee.controller'
import { requireAuth } from '../../../controllers/auth.controller'
import {
requestBodyValidator,
requestQueryValidator
} from '../../../middlewares/requestValidator'
import {
getAllMenteeEmailsSchema,
getMenteesSchema,
updateMenteeStatusSchema
} from '../../../schemas/admin/admin.mentee-routes.schema'

const menteeRouter = express.Router()

menteeRouter.get('/emails/', requireAuth, getAllMenteeEmails)
menteeRouter.get('/applications', requireAuth, getMentees)
menteeRouter.get(
'/emails/',
[requireAuth, requestQueryValidator(getAllMenteeEmailsSchema)],
getAllMenteeEmails
)
menteeRouter.get(
'/applications',
[requireAuth, requestQueryValidator(getMenteesSchema)],
getMentees
)
menteeRouter.get('/:menteeId', requireAuth, getMenteeDetails)
menteeRouter.put('/:menteeId/state', requireAuth, updateMenteeStatus)
menteeRouter.put(
'/:menteeId/state',
[requireAuth, requestBodyValidator(updateMenteeStatusSchema)],
updateMenteeStatus
)

export default menteeRouter
39 changes: 33 additions & 6 deletions src/routes/admin/mentor/mentor.route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import express from 'express'
import { requireAuth } from '../../../controllers/auth.controller'
import {
getAllMentorEmails,
getAllMentorsByStatus,
Expand All @@ -8,18 +7,46 @@ import {
searchMentors,
updateMentorAvailability
} from '../../../controllers/admin/mentor.controller'
import { requireAuth } from '../../../controllers/auth.controller'
import {
requestBodyValidator,
requestQueryValidator
} from '../../../middlewares/requestValidator'
import {
getAllMentorEmailsSchema,
getAllMentorsByStatusSchema,
mentorStatusSchema,
searchMentorsSchema,
updateMentorAvailabilitySchema
} from '../../../schemas/admin/admin.mentor-routes.schema'

const mentorRouter = express.Router()

mentorRouter.put('/:mentorId/state', requireAuth, mentorStatusHandler)
mentorRouter.put(
'/:mentorId/state',
[requireAuth, requestBodyValidator(mentorStatusSchema)],
mentorStatusHandler
)
mentorRouter.get('/:mentorId', requireAuth, mentorDetailsHandler)
mentorRouter.get('/', requireAuth, getAllMentorsByStatus)
mentorRouter.get('/emails', requireAuth, getAllMentorEmails)
mentorRouter.get(
'/',
[requireAuth, requestQueryValidator(getAllMentorsByStatusSchema)],
getAllMentorsByStatus
)
mentorRouter.get(
'/emails',
[requireAuth, requestQueryValidator(getAllMentorEmailsSchema)],
getAllMentorEmails
)
mentorRouter.put(
'/:mentorId/availability',
requireAuth,
[requireAuth, requestBodyValidator(updateMentorAvailabilitySchema)],
updateMentorAvailability
)
mentorRouter.get('/search', requireAuth, searchMentors)
mentorRouter.get(
'/search',
[requireAuth, requestQueryValidator(searchMentorsSchema)],
searchMentors
)

export default mentorRouter
6 changes: 4 additions & 2 deletions src/routes/auth/auth.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import {
passwordResetRequest,
register
} from '../../controllers/auth.controller'
import { requestBodyValidator } from '../../middlewares/requestValidator'
import { loginSchema, registerSchema } from '../../schemas/auth-routes.schems'

const authRouter = express.Router()

authRouter.post('/register', register)
authRouter.post('/login', login)
authRouter.post('/register', requestBodyValidator(registerSchema), register)
authRouter.post('/login', requestBodyValidator(loginSchema), login)
authRouter.get('/logout', logout)

authRouter.get(
Expand Down
8 changes: 7 additions & 1 deletion src/routes/emails/emails.route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import express from 'express'
import { sendEmailController } from '../../controllers/admin/email.controller'
import { requireAuth } from '../../controllers/auth.controller'
import { requestBodyValidator } from '../../middlewares/requestValidator'
import { sendEmailSchema } from '../../schemas/email-routes.schema'

const emailRouter = express.Router()

emailRouter.post('/send', requireAuth, sendEmailController)
emailRouter.post(
'/send',
[requireAuth, requestBodyValidator(sendEmailSchema)],
sendEmailController
)

export default emailRouter
21 changes: 17 additions & 4 deletions src/routes/mentee/mentee.route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import express from 'express'
import { requireAuth } from '../../controllers/auth.controller'
import {
getMenteeDetails,
menteeApplicationHandler,
updateMenteeStatus,
getMenteeDetails
updateMenteeStatus
} from '../../controllers/mentee.controller'
import { requestBodyValidator } from '../../middlewares/requestValidator'
import {
menteeApplicationSchema,
updateMenteeStatusSchema
} from '../../schemas/mentee-routes.schemas'

const menteeRouter = express.Router()

menteeRouter.post('/', requireAuth, menteeApplicationHandler)
menteeRouter.post(
'/',
[requireAuth, requestBodyValidator(menteeApplicationSchema)],
menteeApplicationHandler
)
menteeRouter.get('/:menteeId', getMenteeDetails)
menteeRouter.put('/:menteeId/status/', requireAuth, updateMenteeStatus)
menteeRouter.put(
'/:menteeId/status/',
[requireAuth, requestBodyValidator(updateMenteeStatusSchema)],
updateMenteeStatus
)

export default menteeRouter
26 changes: 21 additions & 5 deletions src/routes/mentor/mentor.route.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import express from 'express'
import {
requestBodyValidator,
requestQueryValidator
} from '../../middlewares/requestValidator'
import {
getMenteesByMentorSchema,
mentorApplicationSchema
} from '../../schemas/mentor-routes.schema'
import { requireAuth } from './../../controllers/auth.controller'
import {
getAllMentorsHandler,
getMenteesByMentor,
mentorApplicationHandler,
mentorAvailabilityHandler,
mentorDetailsHandler,
getAllMentorsHandler,
getMenteesByMentor
mentorDetailsHandler
} from './../../controllers/mentor.controller'

const mentorRouter = express.Router()

mentorRouter.post('/', requireAuth, mentorApplicationHandler)
mentorRouter.get('/mentees', requireAuth, getMenteesByMentor)
mentorRouter.post(
'/',
[requireAuth, requestBodyValidator(mentorApplicationSchema)],
mentorApplicationHandler
)
mentorRouter.get(
'/mentees',
[requireAuth, requestQueryValidator(getMenteesByMentorSchema)],
getMenteesByMentor
)
mentorRouter.put(
'/:mentorId/availability',
requireAuth,
Expand Down
22 changes: 19 additions & 3 deletions src/routes/profile/profile.route.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import express from 'express'
import { requireAuth } from '../../controllers/auth.controller'
import {
deleteProfileHandler,
getApplicationsHandler,
getProfileHandler,
updateProfileHandler
} from '../../controllers/profile.controller'
import { requireAuth } from '../../controllers/auth.controller'
import {
requestBodyValidator,
requestQueryValidator
} from '../../middlewares/requestValidator'
import {
getApplicationsSchema,
updateProfileSchema
} from '../../schemas/profile-routes.schema'

const profileRouter = express.Router()

profileRouter.get('/profile', requireAuth, getProfileHandler)
profileRouter.put('/profile', requireAuth, updateProfileHandler)
profileRouter.put(
'/profile',
[requireAuth, requestBodyValidator(updateProfileSchema)],
updateProfileHandler
)
profileRouter.delete('/profile', requireAuth, deleteProfileHandler)
profileRouter.get('/applications', requireAuth, getApplicationsHandler)
profileRouter.get(
'/applications',
[requireAuth, requestQueryValidator(getApplicationsSchema)],
getApplicationsHandler
)

export default profileRouter
9 changes: 9 additions & 0 deletions src/schemas/admin/admin.category-routes.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { z } from 'zod'

export const addCategorySchema = z.object({
categoryName: z.string()
})

export const updateCategorySchema = z.object({
categoryName: z.string()
})
14 changes: 14 additions & 0 deletions src/schemas/admin/admin.mentee-routes.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { z } from 'zod'
import { MenteeApplicationStatus } from '../../enums'

export const getAllMenteeEmailsSchema = z.object({
status: z.nativeEnum(MenteeApplicationStatus)
})

export const getMenteesSchema = z.object({
state: z.nativeEnum(MenteeApplicationStatus)
})

export const updateMenteeStatusSchema = z.object({
state: z.nativeEnum(MenteeApplicationStatus)
})
Loading

0 comments on commit 135dce9

Please sign in to comment.