Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanitize mentee public endpoint and sanitize mentor details #150

Merged
merged 2 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export const requireAuth = (
const token = req.cookies.jwt

if (!token) {
return res.status(401).json({ error: 'Use is not authenticated' })
return res.status(401).json({ error: 'User is not authenticated' })
}

try {
Expand Down
22 changes: 20 additions & 2 deletions src/controllers/mentee.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type Mentee from '../entities/mentee.entity'
import type Profile from '../entities/profile.entity'
import { getMentee, updateStatus } from '../services/admin/mentee.service'
import { MentorApplicationStatus, StatusUpdatedBy } from '../enums'
import { addMentee } from '../services/mentee.service'
import { addMentee, getPublicMentee } from '../services/mentee.service'

export const menteeApplicationHandler = async (
req: Request,
Expand Down Expand Up @@ -71,7 +71,6 @@ export const getMenteeDetails = async (
): Promise<ApiResponse<Mentee>> => {
try {
const { menteeId } = req.params

const { statusCode, message, mentee } = await getMentee(menteeId)
return res.status(statusCode).json({ mentee, message })
} catch (err) {
Expand All @@ -84,3 +83,22 @@ export const getMenteeDetails = async (
throw err
}
}

export const getPublicMenteeDetails = async (
req: Request,
res: Response
): Promise<ApiResponse<Mentee>> => {
try {
const { menteeId } = req.params
const { statusCode, message, mentee } = await getPublicMentee(menteeId)
return res.status(statusCode).json({ mentee, message })
} catch (err) {
if (err instanceof Error) {
console.error('Error executing query', err)
return res
.status(500)
.json({ error: 'Internal server error', message: err.message })
}
throw err
}
}
4 changes: 3 additions & 1 deletion src/routes/mentee/mentee.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from 'express'
import { requireAuth } from '../../controllers/auth.controller'
import {
getMenteeDetails,
getPublicMenteeDetails,
menteeApplicationHandler,
updateMenteeStatus
} from '../../controllers/mentee.controller'
Expand All @@ -18,7 +19,8 @@ menteeRouter.post(
[requireAuth, requestBodyValidator(menteeApplicationSchema)],
menteeApplicationHandler
)
menteeRouter.get('/:menteeId', getMenteeDetails)
menteeRouter.get('/:menteeId', requireAuth, getMenteeDetails)
menteeRouter.get('/public/:menteeId', getPublicMenteeDetails)
menteeRouter.put(
'/:menteeId/status/',
[requireAuth, requestBodyValidator(updateMenteeStatusSchema)],
Expand Down
2 changes: 1 addition & 1 deletion src/schemas/admin/admin.mentee-routes.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const getAllMenteeEmailsSchema = z.object({
})

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

export const updateMenteeStatusSchema = z.object({
Expand Down
3 changes: 2 additions & 1 deletion src/scripts/seed-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Profile from '../entities/profile.entity'
import {
EmailStatusTypes,
MenteeApplicationStatus,
MentorApplicationStatus,
ProfileTypes
} from '../enums'

Expand Down Expand Up @@ -129,7 +130,7 @@ const createRandomProfile = (): Partial<Profile> => {

const createMentor = (category: Category, profile: Profile): Mentor => {
return {
state: faker.helpers.enumValue(MenteeApplicationStatus),
state: faker.helpers.enumValue(MentorApplicationStatus),
category,
application: {
firstName: faker.person.firstName(),
Expand Down
41 changes: 40 additions & 1 deletion src/services/mentee.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import Mentee from '../entities/mentee.entity'
import Mentor from '../entities/mentor.entity'
import type Profile from '../entities/profile.entity'
import { MenteeApplicationStatus } from '../enums'
import { getEmailContent, getMentorNotifyEmailContent } from '../utils'
import {
getEmailContent,
getMentorNotifyEmailContent,
getMenteePublicData
} from '../utils'
import { sendEmail } from './admin/email.service'

export const addMentee = async (
Expand Down Expand Up @@ -116,3 +120,38 @@ export const addMentee = async (
throw new Error('Error adding mentee')
}
}

export const getPublicMentee = async (
menteeId: string
): Promise<{
statusCode: number
mentee: Mentee | null
message: string
}> => {
try {
const menteeRepository = dataSource.getRepository(Mentee)

const mentee = await menteeRepository.findOne({
where: { uuid: menteeId },
relations: ['profile', 'mentor', 'mentor.profile']
})

if (!mentee) {
return {
statusCode: 404,
mentee: null,
message: 'Mentee not found'
}
}

const publicMentee = getMenteePublicData(mentee)

return {
statusCode: 200,
mentee: publicMentee,
message: 'Mentees found'
}
} catch (err) {
throw new Error('Error getting mentees')
}
}
9 changes: 3 additions & 6 deletions src/services/mentor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export const getMentor = async (
const mentorRepository = dataSource.getRepository(Mentor)
const mentor = await mentorRepository.findOne({
where: { uuid: mentorId },
relations: ['profile', 'category', 'mentees'],
relations: ['profile', 'category', 'mentees', 'mentees.profile'],
select: ['application', 'uuid', 'availability']
})

Expand All @@ -160,14 +160,11 @@ export const getMentor = async (
}
}

const { application } = mentor
delete application.cv
delete application.contactNo
delete application.email
const publicMentor = getMentorPublicData(mentor)

return {
statusCode: 200,
mentor,
mentor: publicMentor,
message: 'Mentor found'
}
} catch (err) {
Expand Down
36 changes: 34 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { generateCertificate } from './services/admin/generateCertificate'
import { randomUUID } from 'crypto'
import { certificatesDir } from './app'
import type Mentee from './entities/mentee.entity'

export const signAndSetCookie = (res: Response, uuid: string): void => {
const token = jwt.sign({ userId: uuid }, JWT_SECRET ?? '')
Expand All @@ -21,14 +22,45 @@
}

export const getMentorPublicData = (mentor: Mentor): Mentor => {
const { application } = mentor
const { application, profile } = mentor

delete application.cv
delete application.contactNo
delete application.email
delete application.motivation
delete application.reasonToMentor

delete profile.created_at
delete profile.updated_at

if (mentor.mentees) {
mentor.mentees = mentor.mentees.map((mentee) => {
return getMenteePublicData(mentee)
})
}

return mentor
}

export const getMenteePublicData = (mentee: Mentee): Mentee => {
const { application, profile } = mentee

delete application.cv
delete application.contactNo
delete application.email
delete application.submission
delete application.consentGiven

delete profile.created_at
delete profile.updated_at

if (mentee.mentor) {
mentee.mentor = getMentorPublicData(mentee.mentor)
}

return mentee
}

export const checkProfilePictureFileType = (
file: Express.Multer.File,
cb: multer.FileFilterCallback
Expand Down Expand Up @@ -68,7 +100,7 @@
subject: string
message: string
}
): any => {

Check warning on line 103 in src/utils.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
const templatePath = path.join(__dirname, 'templates', `${templateName}.ejs`)

return new Promise<string>((resolve, reject) => {
Expand Down Expand Up @@ -101,7 +133,7 @@
return {
subject: 'Thank you very much for applying to ScholarX',
message: `Dear ${name},<br /><br />
Thank you very much for applying to ScholarX. Your application has been received. Our team will soon review your application, and we will keep you posted on the progress via email.
Thank you very much for applying to ScholarX. Your application has been received. Our team will soon review your application, and we will keep you posted on the progress via email.
Please reach out to us via <a href="mailto:sustainableedufoundation@gmail.com">sustainableedufoundation@gmail.com</a> for any clarifications.`
}
case MentorApplicationStatus.APPROVED:
Expand Down
Loading