Skip to content

Commit

Permalink
Merge pull request #59 from JohnChia123/main
Browse files Browse the repository at this point in the history
Create API to retrieve all details for particular question attempt made by user
  • Loading branch information
JohnChia123 authored Nov 5, 2024
2 parents ec7f544 + 6b87492 commit 7aeedd7
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 6 deletions.
39 changes: 38 additions & 1 deletion backend/user-service/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,8 @@ Records a question attempt for a user, either creating a new record or updating
```json
{
"questionId": "18",
"timeSpent": 120
"timeSpent": 120, // Time spent on the question in seconds
"code": "function solve() { ... }" // User's code submission for the attempt
}
- **Response Format** (JSON):
- **Code**: 200
Expand All @@ -500,3 +501,39 @@ Fetches the statistics for a user, including the number of questions attempted,
"totalAttempts": 4
}
```

#### 4. Retrieve question attempt details for a User

Retrieve all details for a particular question attempt made by a user.

- **Endpoint**: `GET /users/history/:userId/question/:questionId`
- **Request Parameters**:
- `userId` (string): The unique identifier of the user whose statistics are being fetched.
- `questionId` (number): The id (not _id) of the question.
- **Response Format** (JSON):
- **Code**: 200
- **Body**:
```json
{
"attemptDate": "2024-11-05T22:27:38.534Z",
"attemptCount": 3,
"attemptTime": 30,
"code": "function add(x, y){\r\n return x + y;\r\n}\r\n\r\nfunction substract(x, y) {\r\n return x - y;\r\n}\r\n\r\nconst addition = add(1, 2);\r\n",
"question": {
"id": 19,
"title": "Chalkboard XOR Game",
"complexity": "Hard",
"category": [
"Brainteaser"
],
"description": "You are given an array of integers `nums` represents the numbers written on a chalkboard.\n\nAlice and Bob take turns erasing exactly one number from the chalkboard, with Alice starting first. If erasing a number causes the bitwise XOR of all the elements of the chalkboard to become `0`, then that player loses. The bitwise XOR of one element is that element itself, and the bitwise XOR of no elements is `0`.\n\nAlso, if any player starts their turn with the bitwise XOR of all the elements of the chalkboard equal to `0`, then that player wins.\n\nReturn `true` *if and only if Alice wins the game, assuming both players play optimally*.",
"link": "https://leetcode.com/problems/chalkboard-xor-game/"
}
}
```
- **Code**: 404
- **Body**:
```json
{
"message": "No details found for this question attempt."
}
39 changes: 37 additions & 2 deletions backend/user-service/controller/user-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
getTotalQuestionsAvailable as _getTotalQuestionsAvailable,
updateUserById as _updateUserById,
updateUserPrivilegeById as _updateUserPrivilegeById,
findQuestionAttemptDetails as _findQuestionAttemptDetails,
} from "../model/repository.js";

export async function createUser(req, res) {
Expand Down Expand Up @@ -247,7 +248,7 @@ export async function getUserHistory(req, res) {
export async function addQuestionAttempt(req, res) {
try {
const userId = req.params.userId;
const { questionId, timeSpent } = req.body;
const { questionId, timeSpent, code} = req.body;

const parsedId = Number(questionId);
console.log(parsedId);
Expand All @@ -272,7 +273,7 @@ export async function addQuestionAttempt(req, res) {

console.log("Found question:", question);
// Add or update the question attempt in the user's question history
const updated = await _addOrUpdateQuestionHistory(userId, question._id, timeSpent);
const updated = await _addOrUpdateQuestionHistory(userId, question._id, timeSpent, code);

if (updated) {
return res.status(200).json({ message: "Question history updated successfully." });
Expand Down Expand Up @@ -313,6 +314,40 @@ export async function getUserStats(req, res) {
}
}

export async function getQuestionAttemptDetails(req, res) {
const userId = req.params.userId;
const questionId = req.params.questionId;
const parsedId = Number(questionId);
console.log(parsedId);

if (typeof parsedId !== 'number') {
return res.status(400).json({ message: "Invalid question ID" });
}

const questionServiceUrl = `http://question:2000/questions/byId/${parsedId}`;


// Fetch question data from question-service
const response = await axios.get(questionServiceUrl);
const question = response.data;

console.log("Found question:", question);

try {
const attemptDetails = await _findQuestionAttemptDetails(userId, question._id);

if (attemptDetails) {
return res.status(200).json(attemptDetails);
} else {
return res.status(404).json({ message: "No details found for this question attempt." });
}
} catch (err) {
console.error("Error fetching question attempt details:", err);
return res.status(500).json({ message: "Unknown error when fetching question attempt details!" });
}
}


export function formatUserResponse(user) {
return {
id: user.id,
Expand Down
4 changes: 4 additions & 0 deletions backend/user-service/model/questionHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const QuestionHistorySchema = new mongoose.Schema({
type: Number, // time in seconds
required: true,
},
code: {
type: String,
required: true,
}
});

export default mongoose.model("QuestionHistory", QuestionHistorySchema);
40 changes: 38 additions & 2 deletions backend/user-service/model/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ export async function getTotalQuestionsAvailable() {
return response.data.length;
}

export async function addOrUpdateQuestionHistory(userId, questionId, timeSpent) {
export async function addOrUpdateQuestionHistory(userId, questionId, timeSpent, code) {
try {
console.log("Received data in addOrUpdateQuestionHistory:", { userId, questionId, timeSpent });
console.log("Received data in addOrUpdateQuestionHistory:", { userId, questionId, timeSpent, code});

// Try to find an existing record
console.log("Attempting to find existing history with userId and questionId...");
Expand All @@ -179,6 +179,7 @@ export async function addOrUpdateQuestionHistory(userId, questionId, timeSpent)
existingHistory.attemptCount += 1;
existingHistory.attemptTime += timeSpent;
existingHistory.attemptDate = new Date();
existingHistory.code = code;

// Try to save the updated document
await existingHistory.save();
Expand All @@ -194,6 +195,7 @@ export async function addOrUpdateQuestionHistory(userId, questionId, timeSpent)
attemptDate: new Date(),
attemptCount: 1,
attemptTime: timeSpent,
code: code,
});

// Try to save the new document
Expand All @@ -206,3 +208,37 @@ export async function addOrUpdateQuestionHistory(userId, questionId, timeSpent)
throw new Error("Failed to add or update question history");
}
}

export async function findQuestionAttemptDetails(userId, questionId) {
// Step 1: Find the question attempt record for the user
const attempt = await QuestionHistory.findOne({ userId, question: questionId });

if (attempt) {
let questionDetails = null;
try {
// Step 2: Fetch question details from question-service
const response = await axios.get(`http://question:2000/questions/byObjectId/${questionId}`);
questionDetails = response.data;
} catch (error) {
console.error(`Error fetching question details for questionId ${questionId}:`, error);
}

// Step 3: Construct the response
return {
attemptDate: attempt.attemptDate,
attemptCount: attempt.attemptCount,
attemptTime: attempt.attemptTime,
code: attempt.code,
question: questionDetails ? {
id: questionDetails.id,
title: questionDetails.title,
complexity: questionDetails.complexity,
category: questionDetails.category,
description: questionDetails.description,
link: questionDetails.link,
} : null,
};
}

return null;
}
5 changes: 4 additions & 1 deletion backend/user-service/routes/user-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
checkUserExistByEmailorId,
getUser,
getUserHistory,
getUserStats,
getQuestionAttemptDetails,
getUserStats,
addQuestionAttempt,
updateUser,
updateUserPrivilege,
Expand All @@ -24,6 +25,8 @@ router.get("/history/:userId/stats", verifyAccessToken, getUserStats);

router.get("/history/:userId", verifyAccessToken, getUserHistory);

router.get("/history/:userId/question/:questionId", verifyAccessToken, getQuestionAttemptDetails);

router.patch("/:id/privilege", verifyAccessToken, verifyIsAdmin, updateUserPrivilege);

router.post("/", createUser);
Expand Down

0 comments on commit 7aeedd7

Please sign in to comment.