Skip to content

Commit

Permalink
change in schema for leaderboard
Browse files Browse the repository at this point in the history
Signed-off-by: ayushka11 <gargayushka@gmail.com>
  • Loading branch information
ayushka11 committed Sep 20, 2024
1 parent 14585ee commit c202062
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 192 deletions.
58 changes: 45 additions & 13 deletions src/controllers/checkQuiz/generateLeaderBoard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import LeaderboardModel from '@models/leaderboard/leaderboardModel';
import LeaderboardModel from '@models/leaderboard/sectionLeaderboardModel';
import ResponseModel from '@models/response/responseModel';
import UserModel from '@models/user/userModel';
import sendFailureResponse from '@utils/failureResponse';
Expand All @@ -10,6 +10,7 @@ import { ResponseStatus } from 'types';
interface generateLeaderBoardRequest extends Request {
params: {
quizId: string;
sectionIndex?: string;
};
query: {
search?: string;
Expand All @@ -19,6 +20,8 @@ interface generateLeaderBoardRequest extends Request {
interface Participant {
userId: Types.ObjectId;
marks: number;
sectionMarks: number[];
totalMarks: number;
questionsAttempted: number;
questionsChecked: number;
}
Expand All @@ -38,24 +41,50 @@ function prefixSearch(searchQuery: string, name: string, phoneNumber: string) {
const generateLeaderBoard = async (req: generateLeaderBoardRequest, res: Response) => {
const { quizId } = req.params;
const searchQuery = req.query.search as string;

const sectionIndex = req.params.sectionIndex;

let sectionIndexNum: number | null = null;
if (sectionIndex && sectionIndex !== 'null') {
sectionIndexNum = parseInt(sectionIndex, 10);
if (isNaN(sectionIndexNum)) {
return sendFailureResponse({
res,
error: new Error('Invalid section index'),
messageToSend: 'Invalid section index',
});
}
}
try {
const quiz = await getQuiz(quizId);
const participants: Participant[] = [];

await Promise.all(
quiz?.participants?.map(async (participant) => {
const responses = await ResponseModel.find({ quizId: quizId, userId: participant.userId });

let score = 0;
quiz.participants?.map(async (participant) => {
let totalMarks = 0;
const sectionMarks: number[] = new Array(quiz.sections.length).fill(0);
let questionsAttempted = 0;
let questionsChecked = 0;

responses.forEach((response) => {
score += response.marksAwarded || 0;
questionsAttempted++;
questionsChecked += response.status === ResponseStatus.checked ? 1 : 0;
});
await Promise.all(
quiz.sections.map(async (section, sectionIdx) => {
await Promise.all(
section.questions.map(async (question) => {
const response = await ResponseModel.findOne({
quizId,
questionId: question._id,
userId: participant.userId,
});

if (response) {
sectionMarks[sectionIdx] += response.marksAwarded || 0;
totalMarks += response.marksAwarded || 0;
questionsAttempted++;
questionsChecked += response.status === ResponseStatus.checked ? 1 : 0;
}
}),
);
}),
);

const user = await UserModel.findById(participant.userId);

Expand All @@ -67,7 +96,9 @@ const generateLeaderBoard = async (req: generateLeaderBoardRequest, res: Respons
) {
const leaderboardEntry: Participant = {
userId: participant.userId,
marks: score,
sectionMarks: sectionMarks,
totalMarks: totalMarks,
marks: sectionIndexNum == null ? totalMarks : sectionMarks[sectionIndexNum],
questionsAttempted: questionsAttempted,
questionsChecked: questionsChecked,
};
Expand All @@ -79,6 +110,7 @@ const generateLeaderBoard = async (req: generateLeaderBoardRequest, res: Respons
);

const sortedParticipants = participants.sort((a, b) => b.marks - a.marks);
console.log(sortedParticipants);
await LeaderboardModel.findOneAndUpdate(
{ quizId: quizId },
{
Expand All @@ -101,4 +133,4 @@ const generateLeaderBoard = async (req: generateLeaderBoardRequest, res: Respons
}
};

export default generateLeaderBoard;
export default generateLeaderBoard;
258 changes: 129 additions & 129 deletions src/controllers/checkQuiz/generateSectionLeaderboard.ts
Original file line number Diff line number Diff line change
@@ -1,129 +1,129 @@
import SectionLeaderboardModel from "@models/leaderboard/sectionLeaderboardModel";
import ResponseModel from "@models/response/responseModel";
import UserModel from '@models/user/userModel';
import sendFailureResponse from "@utils/failureResponse";
import getQuiz from "@utils/getQuiz";
import sendInvalidInputResponse from "@utils/invalidInputResponse";
import { Request, Response } from "express";
import { Types } from "mongoose";
import { ResponseStatus } from "types";

interface generateSectionLeaderboardRequest extends Request {
params: {
quizId: string;
sectionIndex: string;
};
query: {
search: string;
searchQuery?: string;
};
}

interface Participant {
userId: Types.ObjectId;
marks: number;
questionsAttempted: number;
questionsChecked: number;
}

function prefixSearch(searchQuery: string, name: string, phoneNumber: string) {
if (!searchQuery || searchQuery === '') return true;
if (/^\d+$/.test(searchQuery)) {
return phoneNumber.startsWith(searchQuery);
}
if (/^[a-zA-Z]+$/.test(searchQuery)) {
return name.toLowerCase().startsWith(searchQuery.toLowerCase());
}
return false;
}

const generateSectionLeaderBoard = async (req: generateSectionLeaderboardRequest, res: Response) => {
const { quizId } = req.params;
const sectionIndex = parseInt(req.params.sectionIndex, 10);
const searchQuery = req.query.search as string;

try {
const quiz = await getQuiz(quizId);
if (!quiz || !quiz?.sections || sectionIndex >= quiz.sections.length) {
return sendInvalidInputResponse(res);
}

const sectionQuestions = quiz.sections[sectionIndex]?.questions || [];
const participants: Participant[] = [];

for (const participant of quiz.participants || []) {
const { userId } = participant;

let marks = 0;
let questionsAttempted = 0;
let questionsChecked = 0;

for (const question of sectionQuestions) {
const response = await ResponseModel.findOne({
quizId,
questionId: question._id,
userId
});

if (response) {
marks += response.marksAwarded || 0;
questionsAttempted++;
questionsChecked += response.status === ResponseStatus.checked ? 1 : 0;
}
}

if (Types.ObjectId.isValid(userId)) {
participants.push({
userId: userId,
marks,
questionsAttempted,
questionsChecked,
});
}
}

const filteredParticipantsPromises = participants.map(async (participant) => {
const user = await UserModel.findById(participant.userId);
if (user) {
const name = user.personalDetails?.name?.toLowerCase() || "";
const phoneNumber = user.personalDetails?.phoneNo || "";
if (prefixSearch(searchQuery, name, phoneNumber)) {
return participant;
}
}
return null;
});

const filteredParticipants = (await Promise.all(filteredParticipantsPromises)).filter((p): p is Participant => p !== null);

const sortedParticipants = filteredParticipants.sort((a, b) => b.marks - a.marks);

await SectionLeaderboardModel.findOneAndUpdate(
{
quizId,
sectionIndex
},
{
quizId,
sectionIndex,
participants: sortedParticipants,
},
{
upsert: true,
},
);

return res.status(200).json({
message: `Leaderboard for section ${sectionIndex} generated successfully`,
leaderboard: sortedParticipants,
});
} catch (error: unknown) {
return sendFailureResponse({
res,
error,
messageToSend: 'Failed to generate leaderboard',
});
}
};

export default generateSectionLeaderBoard;
// import SectionLeaderboardModel from "@models/leaderboard/sectionLeaderboardModel";
// import ResponseModel from "@models/response/responseModel";
// import UserModel from '@models/user/userModel';
// import sendFailureResponse from "@utils/failureResponse";
// import getQuiz from "@utils/getQuiz";
// import sendInvalidInputResponse from "@utils/invalidInputResponse";
// import { Request, Response } from "express";
// import { Types } from "mongoose";
// import { ResponseStatus } from "types";

// interface generateSectionLeaderboardRequest extends Request {
// params: {
// quizId: string;
// sectionIndex: string;
// };
// query: {
// search: string;
// searchQuery?: string;
// };
// }

// interface Participant {
// userId: Types.ObjectId;
// marks: number;
// questionsAttempted: number;
// questionsChecked: number;
// }

// function prefixSearch(searchQuery: string, name: string, phoneNumber: string) {
// if (!searchQuery || searchQuery === '') return true;
// if (/^\d+$/.test(searchQuery)) {
// return phoneNumber.startsWith(searchQuery);
// }
// if (/^[a-zA-Z]+$/.test(searchQuery)) {
// return name.toLowerCase().startsWith(searchQuery.toLowerCase());
// }
// return false;
// }

// const generateSectionLeaderBoard = async (req: generateSectionLeaderboardRequest, res: Response) => {
// const { quizId } = req.params;
// const sectionIndex = parseInt(req.params.sectionIndex, 10);
// const searchQuery = req.query.search as string;

// try {
// const quiz = await getQuiz(quizId);
// if (!quiz || !quiz?.sections || sectionIndex >= quiz.sections.length) {
// return sendInvalidInputResponse(res);
// }

// const sectionQuestions = quiz.sections[sectionIndex]?.questions || [];
// const participants: Participant[] = [];

// for (const participant of quiz.participants || []) {
// const { userId } = participant;

// let marks = 0;
// let questionsAttempted = 0;
// let questionsChecked = 0;

// for (const question of sectionQuestions) {
// const response = await ResponseModel.findOne({
// quizId,
// questionId: question._id,
// userId
// });

// if (response) {
// marks += response.marksAwarded || 0;
// questionsAttempted++;
// questionsChecked += response.status === ResponseStatus.checked ? 1 : 0;
// }
// }

// if (Types.ObjectId.isValid(userId)) {
// participants.push({
// userId: userId,
// marks,
// questionsAttempted,
// questionsChecked,
// });
// }
// }

// const filteredParticipantsPromises = participants.map(async (participant) => {
// const user = await UserModel.findById(participant.userId);
// if (user) {
// const name = user.personalDetails?.name?.toLowerCase() || "";
// const phoneNumber = user.personalDetails?.phoneNo || "";
// if (prefixSearch(searchQuery, name, phoneNumber)) {
// return participant;
// }
// }
// return null;
// });

// const filteredParticipants = (await Promise.all(filteredParticipantsPromises)).filter((p): p is Participant => p !== null);

// const sortedParticipants = filteredParticipants.sort((a, b) => b.marks - a.marks);

// await SectionLeaderboardModel.findOneAndUpdate(
// {
// quizId,
// sectionIndex
// },
// {
// quizId,
// sectionIndex,
// participants: sortedParticipants,
// },
// {
// upsert: true,
// },
// );

// return res.status(200).json({
// message: `Leaderboard for section ${sectionIndex} generated successfully`,
// leaderboard: sortedParticipants,
// });
// } catch (error: unknown) {
// return sendFailureResponse({
// res,
// error,
// messageToSend: 'Failed to generate leaderboard',
// });
// }
// };

// export default generateSectionLeaderBoard;
2 changes: 1 addition & 1 deletion src/controllers/checkQuiz/getCheckingDashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Request, Response } from 'express';
import QuizModel from '@models/quiz/quizModel';
import sendInvalidInputResponse from '@utils/invalidInputResponse';
import sendFailureResponse from '@utils/failureResponse';
import LeaderboardModel from '@models/leaderboard/leaderboardModel';
import LeaderboardModel from '@models/leaderboard/sectionLeaderboardModel';
import UserModel from '@models/user/userModel';
import { Types } from 'mongoose';

Expand Down
10 changes: 5 additions & 5 deletions src/models/leaderboard/leaderboardModel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import mongoose from 'mongoose'
import { ModelNames, ILeaderboard } from 'types'
import leaderboardSchema from './leaderboardSchema'
// import mongoose from 'mongoose'
// import { ModelNames, ILeaderboard } from 'types'
// import leaderboardSchema from './leaderboardSchema'

const LeaderboardModel = mongoose.model<ILeaderboard>(ModelNames.Leaderboard, leaderboardSchema)
// const LeaderboardModel = mongoose.model<ILeaderboard>(ModelNames.Leaderboard, leaderboardSchema)

export default LeaderboardModel
// export default LeaderboardModel
Loading

0 comments on commit c202062

Please sign in to comment.