Skip to content
Open
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
16 changes: 10 additions & 6 deletions src/controllers/checkQuiz/response/getAllResponses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const getAllResponses = async (req: getAllResponsesRequest, res: Response) => {
const question = await QuestionModel.findById(questionId)
if (!question) {
sendInvalidInputResponse(res)
return
}
const responses = await ResponseModel.find({ questionId, quizId }).populate({
path: 'userId',
Expand All @@ -30,21 +31,24 @@ const getAllResponses = async (req: getAllResponsesRequest, res: Response) => {
}
})

const firstResponse = await ResponseModel.findById(responsesToSend[0].responseId).populate({
path: 'checkedBy',
select: 'personalDetails.name personalDetails.emailAdd',
})
let firstResponse = null
if (responsesToSend.length > 0) {
firstResponse = await ResponseModel.findById(responsesToSend[0].responseId).populate({
path: 'checkedBy',
select: 'personalDetails.name personalDetails.emailAdd',
})
}

return res.status(200).json({
responses: responsesToSend || [],
firstResponse: {
firstResponse: firstResponse ? {
user: firstResponse?.userId,
selectedOptionId: firstResponse?.selectedOptionId,
subjectiveAnswer: firstResponse?.subjectiveAnswer,
marksAwarded: firstResponse?.marksAwarded,
status: firstResponse?.status,
checkedBy: firstResponse?.checkedBy,
},
} : null,
// TODO: to remove, Frontend Issue
questionId: question?._id,
})
Expand Down
111 changes: 111 additions & 0 deletions src/controllers/checkQuiz/response/getUserResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import QuizModel from '@models/quiz/quizModel'
import ResponseModel from '@models/response/responseModel'
import UserModel from '@models/user/userModel'
import sendFailureResponse from '@utils/failureResponse'
import sendInvalidInputResponse from '@utils/invalidInputResponse'
import { Request, Response } from 'express'
import { isValidObjectId } from 'mongoose'

interface GetUserQuizResponsesRequest extends Request {
params: {
quizId: string
userId: string
}
}

interface FormattedResponse {
questionId: any
sectionDetails: string
question: string
marks: {
awarded?: number
max: number
}
response: {
options?: string[]
text?: string
status: string
}
}

const getUserQuizResponses = async (req: GetUserQuizResponsesRequest, res: Response) => {
const { quizId, userId } = req.params

if (!isValidObjectId(quizId) || !isValidObjectId(userId)) {
return sendInvalidInputResponse(res)
}

try {
const [quiz, user] = await Promise.all([
QuizModel.findById(quizId),
UserModel.findById(userId).select('personalDetails')
])

if (!quiz || !user) return sendInvalidInputResponse(res)

const participant = quiz.participants?.find(p => p.userId?.toString() === userId)
if (!participant) return sendInvalidInputResponse(res)

const responses = await ResponseModel.find({ quizId, userId })
.populate<{ questionId: any }>('questionId', 'description type maxMarks')

const questionSectionMap = new Map()
quiz.sections?.forEach((section, sectionIndex) => {
section.questions?.forEach((questionId, questionIndex) => {
questionSectionMap.set(questionId.toString(), {
sectionNumber: sectionIndex + 1,
sectionName: section.name,
questionNumber: questionIndex + 1
})
})
})

const formattedResponses: FormattedResponse[] = responses.map(response => {
const sectionInfo = questionSectionMap.get(response.questionId._id.toString())
return {
questionId: response.questionId._id,
sectionDetails: sectionInfo
? `${sectionInfo.sectionName || `Section ${sectionInfo.sectionNumber}`} - Question ${sectionInfo.questionNumber}`
: 'General Questions',
question: response.questionId.description,
marks: {
awarded: response.marksAwarded,
max: response.questionId.maxMarks
},
response: {
options: Array.isArray(response.selectedOptionId) ? response.selectedOptionId : [],
text: response.subjectiveAnswer,
status: response.status
}
}
})

return res.status(200).json({
userDetails: {
id: user._id,
name: user.personalDetails?.name,
email: user.personalDetails?.emailAdd,
contact: user.personalDetails?.phoneNo
},
quizDetails: {
id: quiz._id,
name: quiz.quizMetadata?.name
},
registration: participant.registrationData?.customFields || [],
evaluation: {
totalMarks: formattedResponses.reduce((sum, r) => sum + (r.marks.awarded || 0), 0),
status: participant.submitted ? 'Submitted' : 'Pending'
},
responses: formattedResponses
})

} catch (error: unknown) {
return sendFailureResponse({
res,
error,
messageToSend: 'Failed to get user quiz responses'
})
}
}

export default getUserQuizResponses
2 changes: 2 additions & 0 deletions src/controllers/checkQuiz/response/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { default as checkResponse } from './checkResponse'
export { default as getResponse } from './getResponse'
export { default as getAllResponses } from './getAllResponses'
export { default as getUserResponses } from './getUserResponse'
export { default as searchParticipant } from './searchParticipant'
49 changes: 49 additions & 0 deletions src/controllers/checkQuiz/response/searchParticipant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import QuizModel from '@models/quiz/quizModel'
import sendFailureResponse from '@utils/failureResponse'
import sendInvalidInputResponse from '@utils/invalidInputResponse'
import { Request, Response } from 'express'
import { isValidObjectId } from 'mongoose'

const searchParticipant = async (req: Request, res: Response) => {
const { quizId } = req.params
const { query } = req.query

if (!query || !isValidObjectId(quizId)) {
return sendInvalidInputResponse(res)
}

try {
const quiz = await QuizModel.findById(quizId)
.populate({
path: 'participants.userId',
select: 'personalDetails',
match: {
$or: [
{ 'personalDetails.emailAdd': query },
{ 'personalDetails.phoneNo': query }
]
}
})

if (!quiz) return sendInvalidInputResponse(res)

const participant = quiz.participants?.find(p => p.userId)
if (!participant) {
return res.status(404).json({ message: 'Participant not found' })
}

return res.status(200).json({
userId: participant.userId?._id,
quizId: quiz._id
})

} catch (error: unknown) {
return sendFailureResponse({
res,
error,
messageToSend: 'Search failed'
})
}
}

export default searchParticipant
2 changes: 2 additions & 0 deletions src/routers/checkQuiz/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from 'express'
import * as checkQuizController from '@controllers/checkQuiz'
import questionRouter from './question'
import responseRouter from './response'
import userRouter from './user'
import hasEditAccess from '@utils/hasEditAccess'
import isQuizAdmin from '@utils/isQuizAdmin'
import isOnboard from '@utils/isOnboard'
Expand All @@ -10,6 +11,7 @@ const router = express.Router()

router.use('/question', questionRouter)
router.use('/response', responseRouter)
router.use('/', userRouter)

router.get('/dashboard/:quizId/:sectionIndex/', isOnboard, hasEditAccess, checkQuizController.getCheckingDashboard)
router.get('/dashboard/:quizId/', isOnboard, hasEditAccess, checkQuizController.getCheckingDashboard)
Expand Down
11 changes: 11 additions & 0 deletions src/routers/checkQuiz/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import express from 'express'
import * as responseController from '@controllers/checkQuiz/response'
import hasEditAccess from '@utils/hasEditAccess'
import isOnboard from '@utils/isOnboard'

const router = express.Router()

router.get('/:quizId/user/:userId',isOnboard, hasEditAccess,responseController.getUserResponses)
router.get('/:quizId/search',isOnboard, hasEditAccess, responseController.searchParticipant)

export default router