Skip to content

Commit

Permalink
Merge pull request #111 from feliciagan/qnhist
Browse files Browse the repository at this point in the history
Qnhist
  • Loading branch information
nicolelim02 authored Nov 8, 2024
2 parents c29ba6b + f9498b0 commit 17de192
Show file tree
Hide file tree
Showing 24 changed files with 437 additions and 272 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe("Code execution routes", () => {
expect(response.body.data).toBeInstanceOf(Array);
expect(response.body.data[0]).toHaveProperty("isMatch", true);
expect(response.body.data[0]["isMatch"]).toBe(true);
expect(response.body.data[1]["isMatch"]).toBe(false);
expect(response.body.data[1]["isMatch"]).toBe(true);
});
});
});
1 change: 1 addition & 0 deletions backend/collab-service/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ ORIGINS=http://localhost:5173,http://127.0.0.1:5173

# Other service APIs
USER_SERVICE_URL=http://user-service:3001/api
QN_HISTORY_SERVICE_URL=http://qn-history-service:3006/api/qnhistories

# Redis configuration
REDIS_URI=redis://collab-service-redis:6379
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,31 @@ const qnHistoryService = axios.create({
});

export const createQuestionHistory = (
userIds: string[],
questionId: string,
title: string,
submissionStatus: string,
code: string,
language: string,
...userIds: string[]
authToken: string
) => {
const dateAttempted = new Date();
return qnHistoryService.post("/", {
userIds,
questionId,
title,
submissionStatus,
language,
dateAttempted,
timeTaken: 0,
});
return qnHistoryService.post(
"/",
{
userIds,
questionId,
title,
submissionStatus,
dateAttempted,
timeTaken: 0,
code,
language,
},
{
headers: {
Authorization: authToken,
},
}
);
};
55 changes: 43 additions & 12 deletions backend/collab-service/src/handlers/websocketHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Socket } from "socket.io";
import { io } from "../server";
import redisClient from "../config/redis";
import { Doc, applyUpdateV2, encodeStateAsUpdateV2 } from "yjs";
import { createQuestionHistory } from "../api/questionHistoryService";

enum CollabEvents {
// Receive
Expand Down Expand Up @@ -55,19 +56,49 @@ export const handleWebsocketCollabEvents = (socket: Socket) => {
}
});

socket.on(CollabEvents.INIT_DOCUMENT, (roomId: string, template: string) => {
const doc = getDocument(roomId);
const isPartnerReady = partnerReadiness.get(roomId);

if (isPartnerReady && doc.getText().length === 0) {
doc.transact(() => {
doc.getText().insert(0, template);
});
io.to(roomId).emit(CollabEvents.DOCUMENT_READY);
} else {
partnerReadiness.set(roomId, true);
socket.on(
CollabEvents.INIT_DOCUMENT,
(
roomId: string,
template: string,
uid1: string,
uid2: string,
language: string,
qnId: string,
qnTitle: string
) => {
const doc = getDocument(roomId);
const isPartnerReady = partnerReadiness.get(roomId);

if (isPartnerReady && doc.getText().length === 0) {
const token =
socket.handshake.headers.authorization || socket.handshake.auth.token;
createQuestionHistory(
[uid1, uid2],
qnId,
qnTitle,
"Attempted",
template,
language,
token
)
.then((res) => {
doc.transact(() => {
doc.getText().insert(0, template);
});
io.to(roomId).emit(
CollabEvents.DOCUMENT_READY,
res.data.qnHistory.id
);
})
.catch((err) => {
console.log(err);
});
} else {
partnerReadiness.set(roomId, true);
}
}
});
);

socket.on(
CollabEvents.UPDATE_REQUEST,
Expand Down
1 change: 0 additions & 1 deletion backend/matching-service/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ ORIGINS=http://localhost:5173,http://127.0.0.1:5173

# Other service APIs
QUESTION_SERVICE_URL=http://question-service:3000/api/questions
QN_HISTORY_SERVICE_URL=http://qn-history-service:3006/api/qnhistories
USER_SERVICE_URL=http://user-service:3001/api

# RabbitMq configuration
Expand Down
23 changes: 6 additions & 17 deletions backend/matching-service/src/handlers/websocketHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
import { io } from "../server";
import { v4 as uuidv4 } from "uuid";
import { getRandomQuestion } from "../api/questionService";
import { createQuestionHistory } from "../api/questionHistoryService";

enum MatchEvents {
// Receive
Expand Down Expand Up @@ -130,23 +129,13 @@ export const handleWebsocketMatchEvents = (socket: Socket) => {
return;
}

const { complexity, category, language } = match;
const { complexity, category } = match;
getRandomQuestion(complexity, category).then((res) => {
const qnId = res.data.question.id;
createQuestionHistory(
qnId,
res.data.question.title,
"Attempted",
language,
userId1,
userId2
).then((res) => {
io.to(matchId).emit(
MatchEvents.MATCH_SUCCESSFUL,
qnId,
res.data.qnHistory.id
);
});
io.to(matchId).emit(
MatchEvents.MATCH_SUCCESSFUL,
res.data.question.id,
res.data.question.title
);
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions backend/qn-history-service/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ SERVICE_PORT=3006
# Origins for cors
ORIGINS=http://localhost:5173,http://127.0.0.1:5173

# Other services
USER_SERVICE_URL=http://user-service:3001/api

# Tests
MONGO_URI_TEST=mongodb://mongo:mongo@test-mongo:27017/

Expand Down
12 changes: 12 additions & 0 deletions backend/qn-history-service/src/api/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axios from "axios";
import dotenv from "dotenv";

dotenv.config();

const USER_SERVICE_URL =
process.env.USER_SERVICE_URL || "http://user-service:3001/api";

export const userClient = axios.create({
baseURL: USER_SERVICE_URL,
withCredentials: true,
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import QnHistory, { IQnHistory } from "../models/QnHistory.ts";
import {
MONGO_OBJ_ID_FORMAT,
MONGO_OBJ_ID_MALFORMED_MESSAGE,
ORDER_INCORRECT_FORMAT_MESSAGE,
PAGE_LIMIT_INCORRECT_FORMAT_MESSAGE,
PAGE_LIMIT_USERID_REQUIRED_MESSAGE,
PAGE_LIMIT_USERID_ORDER_REQUIRED_MESSAGE,
QN_HIST_CREATED_MESSAGE,
QN_HIST_DELETED_MESSAGE,
QN_HIST_NOT_FOUND_MESSAGE,
QN_HIST_RETRIEVED_MESSAGE,
SERVER_ERROR_MESSAGE,
} from "../utils/constants.ts";
import { QnHistListParams } from "../utils/types.ts";

export const createQnHistory = async (
req: Request,
Expand All @@ -24,6 +25,7 @@ export const createQnHistory = async (
submissionStatus,
dateAttempted,
timeTaken,
code,
language,
} = req.body;

Expand All @@ -34,6 +36,7 @@ export const createQnHistory = async (
submissionStatus,
dateAttempted,
timeTaken,
code,
language,
});

Expand Down Expand Up @@ -80,74 +83,81 @@ export const updateQnHistory = async (
}
};

export const deleteQnHistory = async (
req: Request,
res: Response
): Promise<void> => {
try {
const { id } = req.params;

if (!id.match(MONGO_OBJ_ID_FORMAT)) {
res.status(400).json({ message: MONGO_OBJ_ID_MALFORMED_MESSAGE });
return;
}

const currQnHistory = await QnHistory.findById(id);
if (!currQnHistory) {
res.status(404).json({ message: QN_HIST_NOT_FOUND_MESSAGE });
return;
}

await QnHistory.findByIdAndDelete(id);
res.status(200).json({ message: QN_HIST_DELETED_MESSAGE });
} catch (error) {
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
}
};

type QnHistListParams = {
page: string;
qnHistLimit: string;
userId: string;
};

export const readQnHistoryList = async (
req: Request<unknown, unknown, unknown, QnHistListParams>,
res: Response
): Promise<void> => {
try {
const { page, qnHistLimit, userId } = req.query;
const { page, qnHistLimit, userId, title, status, order } = req.query;

if (!page || !qnHistLimit || !userId) {
res.status(400).json({ message: PAGE_LIMIT_USERID_REQUIRED_MESSAGE });
if (!page || !qnHistLimit || !userId || !order) {
res
.status(400)
.json({ message: PAGE_LIMIT_USERID_ORDER_REQUIRED_MESSAGE });
return;
}

const pageInt = parseInt(page, 10);
const qnHistLimitInt = parseInt(qnHistLimit, 10);
const orderInt = parseInt(order, 10);

if (pageInt < 1 || qnHistLimitInt < 1) {
res.status(400).json({ message: PAGE_LIMIT_INCORRECT_FORMAT_MESSAGE });
return;
}

if (orderInt !== 1 && orderInt !== -1) {
res.status(400).json({ message: ORDER_INCORRECT_FORMAT_MESSAGE });
return;
}

if (!userId.match(MONGO_OBJ_ID_FORMAT)) {
res.status(400).json({ message: MONGO_OBJ_ID_MALFORMED_MESSAGE });
return;
}

const filteredQnHistCount = await QnHistory.countDocuments({
userIds: userId,
});
const filteredQnHist = await QnHistory.find({ userIds: userId })
.skip((pageInt - 1) * qnHistLimitInt)
.limit(qnHistLimitInt);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const query: any = {};

res.status(200).json({
message: QN_HIST_RETRIEVED_MESSAGE,
qnHistoryCount: filteredQnHistCount,
qnHistories: filteredQnHist.map(formatQnHistoryResponse),
});
if (title) {
query.title = { $regex: new RegExp(title, "i") };
}

if (status) {
query.submissionStatus = {
$in: Array.isArray(status) ? status : [status],
};
}

query.userIds = { $in: [userId] };

if (orderInt == 1) {
//ascending order
const filteredQnHistCount = await QnHistory.countDocuments(query);
const filteredQnHist = await QnHistory.find(query)
.sort({ dateAttempted: 1 })
.skip((pageInt - 1) * qnHistLimitInt)
.limit(qnHistLimitInt);

res.status(200).json({
message: QN_HIST_RETRIEVED_MESSAGE,
qnHistoryCount: filteredQnHistCount,
qnHistories: filteredQnHist.map(formatQnHistoryResponse),
});
} else {
//descending order
const filteredQnHistCount = await QnHistory.countDocuments(query);
const filteredQnHist = await QnHistory.find(query)
.sort({ dateAttempted: -1 })
.skip((pageInt - 1) * qnHistLimitInt)
.limit(qnHistLimitInt);

res.status(200).json({
message: QN_HIST_RETRIEVED_MESSAGE,
qnHistoryCount: filteredQnHistCount,
qnHistories: filteredQnHist.map(formatQnHistoryResponse),
});
}
} catch (error) {
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
}
Expand Down
17 changes: 17 additions & 0 deletions backend/qn-history-service/src/middlewares/basicAccessControl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NextFunction, Response, Request } from "express";
import { userClient } from "../api/userService";

export const verifyToken = (
req: Request,
res: Response,
next: NextFunction
) => {
const authHeader = req.headers.authorization;
userClient
.get("/auth/verify-token", { headers: { Authorization: authHeader } })
.then(() => next())
.catch((err) => {
console.log(err.response);
return res.status(err.response.status).json(err.response.data);
});
};
Loading

0 comments on commit 17de192

Please sign in to comment.