Skip to content

Commit 17de192

Browse files
authored
Merge pull request #111 from feliciagan/qnhist
Qnhist
2 parents c29ba6b + f9498b0 commit 17de192

File tree

24 files changed

+437
-272
lines changed

24 files changed

+437
-272
lines changed

backend/code-execution-service/tests/codeExecutionRoutes.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe("Code execution routes", () => {
9090
expect(response.body.data).toBeInstanceOf(Array);
9191
expect(response.body.data[0]).toHaveProperty("isMatch", true);
9292
expect(response.body.data[0]["isMatch"]).toBe(true);
93-
expect(response.body.data[1]["isMatch"]).toBe(false);
93+
expect(response.body.data[1]["isMatch"]).toBe(true);
9494
});
9595
});
9696
});

backend/collab-service/.env.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ORIGINS=http://localhost:5173,http://127.0.0.1:5173
66

77
# Other service APIs
88
USER_SERVICE_URL=http://user-service:3001/api
9+
QN_HISTORY_SERVICE_URL=http://qn-history-service:3006/api/qnhistories
910

1011
# Redis configuration
1112
REDIS_URI=redis://collab-service-redis:6379

backend/matching-service/src/api/questionHistoryService.ts renamed to backend/collab-service/src/api/questionHistoryService.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,31 @@ const qnHistoryService = axios.create({
1212
});
1313

1414
export const createQuestionHistory = (
15+
userIds: string[],
1516
questionId: string,
1617
title: string,
1718
submissionStatus: string,
19+
code: string,
1820
language: string,
19-
...userIds: string[]
21+
authToken: string
2022
) => {
2123
const dateAttempted = new Date();
22-
return qnHistoryService.post("/", {
23-
userIds,
24-
questionId,
25-
title,
26-
submissionStatus,
27-
language,
28-
dateAttempted,
29-
timeTaken: 0,
30-
});
24+
return qnHistoryService.post(
25+
"/",
26+
{
27+
userIds,
28+
questionId,
29+
title,
30+
submissionStatus,
31+
dateAttempted,
32+
timeTaken: 0,
33+
code,
34+
language,
35+
},
36+
{
37+
headers: {
38+
Authorization: authToken,
39+
},
40+
}
41+
);
3142
};

backend/collab-service/src/handlers/websocketHandler.ts

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Socket } from "socket.io";
22
import { io } from "../server";
33
import redisClient from "../config/redis";
44
import { Doc, applyUpdateV2, encodeStateAsUpdateV2 } from "yjs";
5+
import { createQuestionHistory } from "../api/questionHistoryService";
56

67
enum CollabEvents {
78
// Receive
@@ -55,19 +56,49 @@ export const handleWebsocketCollabEvents = (socket: Socket) => {
5556
}
5657
});
5758

58-
socket.on(CollabEvents.INIT_DOCUMENT, (roomId: string, template: string) => {
59-
const doc = getDocument(roomId);
60-
const isPartnerReady = partnerReadiness.get(roomId);
61-
62-
if (isPartnerReady && doc.getText().length === 0) {
63-
doc.transact(() => {
64-
doc.getText().insert(0, template);
65-
});
66-
io.to(roomId).emit(CollabEvents.DOCUMENT_READY);
67-
} else {
68-
partnerReadiness.set(roomId, true);
59+
socket.on(
60+
CollabEvents.INIT_DOCUMENT,
61+
(
62+
roomId: string,
63+
template: string,
64+
uid1: string,
65+
uid2: string,
66+
language: string,
67+
qnId: string,
68+
qnTitle: string
69+
) => {
70+
const doc = getDocument(roomId);
71+
const isPartnerReady = partnerReadiness.get(roomId);
72+
73+
if (isPartnerReady && doc.getText().length === 0) {
74+
const token =
75+
socket.handshake.headers.authorization || socket.handshake.auth.token;
76+
createQuestionHistory(
77+
[uid1, uid2],
78+
qnId,
79+
qnTitle,
80+
"Attempted",
81+
template,
82+
language,
83+
token
84+
)
85+
.then((res) => {
86+
doc.transact(() => {
87+
doc.getText().insert(0, template);
88+
});
89+
io.to(roomId).emit(
90+
CollabEvents.DOCUMENT_READY,
91+
res.data.qnHistory.id
92+
);
93+
})
94+
.catch((err) => {
95+
console.log(err);
96+
});
97+
} else {
98+
partnerReadiness.set(roomId, true);
99+
}
69100
}
70-
});
101+
);
71102

72103
socket.on(
73104
CollabEvents.UPDATE_REQUEST,

backend/matching-service/.env.sample

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ ORIGINS=http://localhost:5173,http://127.0.0.1:5173
66

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

1211
# RabbitMq configuration

backend/matching-service/src/handlers/websocketHandler.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
import { io } from "../server";
1313
import { v4 as uuidv4 } from "uuid";
1414
import { getRandomQuestion } from "../api/questionService";
15-
import { createQuestionHistory } from "../api/questionHistoryService";
1615

1716
enum MatchEvents {
1817
// Receive
@@ -130,23 +129,13 @@ export const handleWebsocketMatchEvents = (socket: Socket) => {
130129
return;
131130
}
132131

133-
const { complexity, category, language } = match;
132+
const { complexity, category } = match;
134133
getRandomQuestion(complexity, category).then((res) => {
135-
const qnId = res.data.question.id;
136-
createQuestionHistory(
137-
qnId,
138-
res.data.question.title,
139-
"Attempted",
140-
language,
141-
userId1,
142-
userId2
143-
).then((res) => {
144-
io.to(matchId).emit(
145-
MatchEvents.MATCH_SUCCESSFUL,
146-
qnId,
147-
res.data.qnHistory.id
148-
);
149-
});
134+
io.to(matchId).emit(
135+
MatchEvents.MATCH_SUCCESSFUL,
136+
res.data.question.id,
137+
res.data.question.title
138+
);
150139
});
151140
}
152141
}

backend/qn-history-service/.env.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ SERVICE_PORT=3006
44
# Origins for cors
55
ORIGINS=http://localhost:5173,http://127.0.0.1:5173
66

7+
# Other services
8+
USER_SERVICE_URL=http://user-service:3001/api
9+
710
# Tests
811
MONGO_URI_TEST=mongodb://mongo:mongo@test-mongo:27017/
912

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import axios from "axios";
2+
import dotenv from "dotenv";
3+
4+
dotenv.config();
5+
6+
const USER_SERVICE_URL =
7+
process.env.USER_SERVICE_URL || "http://user-service:3001/api";
8+
9+
export const userClient = axios.create({
10+
baseURL: USER_SERVICE_URL,
11+
withCredentials: true,
12+
});

backend/qn-history-service/src/controllers/questionHistoryController.ts

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import QnHistory, { IQnHistory } from "../models/QnHistory.ts";
33
import {
44
MONGO_OBJ_ID_FORMAT,
55
MONGO_OBJ_ID_MALFORMED_MESSAGE,
6+
ORDER_INCORRECT_FORMAT_MESSAGE,
67
PAGE_LIMIT_INCORRECT_FORMAT_MESSAGE,
7-
PAGE_LIMIT_USERID_REQUIRED_MESSAGE,
8+
PAGE_LIMIT_USERID_ORDER_REQUIRED_MESSAGE,
89
QN_HIST_CREATED_MESSAGE,
9-
QN_HIST_DELETED_MESSAGE,
1010
QN_HIST_NOT_FOUND_MESSAGE,
1111
QN_HIST_RETRIEVED_MESSAGE,
1212
SERVER_ERROR_MESSAGE,
1313
} from "../utils/constants.ts";
14+
import { QnHistListParams } from "../utils/types.ts";
1415

1516
export const createQnHistory = async (
1617
req: Request,
@@ -24,6 +25,7 @@ export const createQnHistory = async (
2425
submissionStatus,
2526
dateAttempted,
2627
timeTaken,
28+
code,
2729
language,
2830
} = req.body;
2931

@@ -34,6 +36,7 @@ export const createQnHistory = async (
3436
submissionStatus,
3537
dateAttempted,
3638
timeTaken,
39+
code,
3740
language,
3841
});
3942

@@ -80,74 +83,81 @@ export const updateQnHistory = async (
8083
}
8184
};
8285

83-
export const deleteQnHistory = async (
84-
req: Request,
85-
res: Response
86-
): Promise<void> => {
87-
try {
88-
const { id } = req.params;
89-
90-
if (!id.match(MONGO_OBJ_ID_FORMAT)) {
91-
res.status(400).json({ message: MONGO_OBJ_ID_MALFORMED_MESSAGE });
92-
return;
93-
}
94-
95-
const currQnHistory = await QnHistory.findById(id);
96-
if (!currQnHistory) {
97-
res.status(404).json({ message: QN_HIST_NOT_FOUND_MESSAGE });
98-
return;
99-
}
100-
101-
await QnHistory.findByIdAndDelete(id);
102-
res.status(200).json({ message: QN_HIST_DELETED_MESSAGE });
103-
} catch (error) {
104-
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
105-
}
106-
};
107-
108-
type QnHistListParams = {
109-
page: string;
110-
qnHistLimit: string;
111-
userId: string;
112-
};
113-
11486
export const readQnHistoryList = async (
11587
req: Request<unknown, unknown, unknown, QnHistListParams>,
11688
res: Response
11789
): Promise<void> => {
11890
try {
119-
const { page, qnHistLimit, userId } = req.query;
91+
const { page, qnHistLimit, userId, title, status, order } = req.query;
12092

121-
if (!page || !qnHistLimit || !userId) {
122-
res.status(400).json({ message: PAGE_LIMIT_USERID_REQUIRED_MESSAGE });
93+
if (!page || !qnHistLimit || !userId || !order) {
94+
res
95+
.status(400)
96+
.json({ message: PAGE_LIMIT_USERID_ORDER_REQUIRED_MESSAGE });
12397
return;
12498
}
12599

126100
const pageInt = parseInt(page, 10);
127101
const qnHistLimitInt = parseInt(qnHistLimit, 10);
102+
const orderInt = parseInt(order, 10);
128103

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

109+
if (orderInt !== 1 && orderInt !== -1) {
110+
res.status(400).json({ message: ORDER_INCORRECT_FORMAT_MESSAGE });
111+
return;
112+
}
113+
134114
if (!userId.match(MONGO_OBJ_ID_FORMAT)) {
135115
res.status(400).json({ message: MONGO_OBJ_ID_MALFORMED_MESSAGE });
136116
return;
137117
}
138118

139-
const filteredQnHistCount = await QnHistory.countDocuments({
140-
userIds: userId,
141-
});
142-
const filteredQnHist = await QnHistory.find({ userIds: userId })
143-
.skip((pageInt - 1) * qnHistLimitInt)
144-
.limit(qnHistLimitInt);
119+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
120+
const query: any = {};
145121

146-
res.status(200).json({
147-
message: QN_HIST_RETRIEVED_MESSAGE,
148-
qnHistoryCount: filteredQnHistCount,
149-
qnHistories: filteredQnHist.map(formatQnHistoryResponse),
150-
});
122+
if (title) {
123+
query.title = { $regex: new RegExp(title, "i") };
124+
}
125+
126+
if (status) {
127+
query.submissionStatus = {
128+
$in: Array.isArray(status) ? status : [status],
129+
};
130+
}
131+
132+
query.userIds = { $in: [userId] };
133+
134+
if (orderInt == 1) {
135+
//ascending order
136+
const filteredQnHistCount = await QnHistory.countDocuments(query);
137+
const filteredQnHist = await QnHistory.find(query)
138+
.sort({ dateAttempted: 1 })
139+
.skip((pageInt - 1) * qnHistLimitInt)
140+
.limit(qnHistLimitInt);
141+
142+
res.status(200).json({
143+
message: QN_HIST_RETRIEVED_MESSAGE,
144+
qnHistoryCount: filteredQnHistCount,
145+
qnHistories: filteredQnHist.map(formatQnHistoryResponse),
146+
});
147+
} else {
148+
//descending order
149+
const filteredQnHistCount = await QnHistory.countDocuments(query);
150+
const filteredQnHist = await QnHistory.find(query)
151+
.sort({ dateAttempted: -1 })
152+
.skip((pageInt - 1) * qnHistLimitInt)
153+
.limit(qnHistLimitInt);
154+
155+
res.status(200).json({
156+
message: QN_HIST_RETRIEVED_MESSAGE,
157+
qnHistoryCount: filteredQnHistCount,
158+
qnHistories: filteredQnHist.map(formatQnHistoryResponse),
159+
});
160+
}
151161
} catch (error) {
152162
res.status(500).json({ message: SERVER_ERROR_MESSAGE, error });
153163
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { NextFunction, Response, Request } from "express";
2+
import { userClient } from "../api/userService";
3+
4+
export const verifyToken = (
5+
req: Request,
6+
res: Response,
7+
next: NextFunction
8+
) => {
9+
const authHeader = req.headers.authorization;
10+
userClient
11+
.get("/auth/verify-token", { headers: { Authorization: authHeader } })
12+
.then(() => next())
13+
.catch((err) => {
14+
console.log(err.response);
15+
return res.status(err.response.status).json(err.response.data);
16+
});
17+
};

0 commit comments

Comments
 (0)