Skip to content

Commit cb9f2d7

Browse files
committed
check POTD and functionality updated
1 parent 66ea3be commit cb9f2d7

File tree

9 files changed

+315
-216
lines changed

9 files changed

+315
-216
lines changed

server/app.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ app.use('/api', typeSenseRoutes);
4343
warmupLeaderboardCache();
4444
startStreakCronJob();
4545

46-
// Schedule leaderboard update every half-hour
46+
// Schedule leaderboard update every 10 minutes
4747
setInterval(() => {
4848
warmupLeaderboardCache();
49-
}, 30 * 60 * 1000);
49+
}, 10 * 60 * 1000);
5050

5151
app.get('/hello', (req, res) => { return res.status(200).send("Hello, World!") })
5252

server/controllers/challengeController.js

Lines changed: 114 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
import { Challenge } from "../models/Challenge.js";
22
import { Solution } from "../models/Solution.js";
33
import { User } from "../models/User.js";
4+
import { fetchLeetCodeStatus, fetchCodeforcesStatus } from "./platformsController.js";
5+
import { postPotdChallenge } from "../utils/postPOTD.js";
6+
import e from "express";
47

58
export const getChallenges = async (req, res) => {
69
try {
7-
const {
8-
category,
9-
difficulty,
10-
status,
11-
search,
10+
const {
11+
category,
12+
difficulty,
13+
status,
14+
search,
1215
userId,
1316
sortBy = 'createdAt',
1417
sortOrder = 'desc'
1518
} = req.query;
16-
19+
1720
const page = parseInt(req.query.page) || 1;
1821
const limit = parseInt(req.query.limit) || 10;
1922
const filter = {};
2023
const authenticatedUser = req.user;
2124

2225
let targetUser = null;
23-
26+
2427
if (userId) {
2528
try {
2629
targetUser = await User.findById(userId).select('solveChallenges _id');
@@ -37,7 +40,7 @@ export const getChallenges = async (req, res) => {
3740
if (category && category !== 'all') {
3841
filter.category = { $in: category.split(',') };
3942
}
40-
43+
4144
if (difficulty && difficulty !== 'all') {
4245
filter.difficulty = { $in: difficulty.split(',') };
4346
}
@@ -95,31 +98,52 @@ export const getChallenges = async (req, res) => {
9598
export const getDailyChallenge = async (req, res) => {
9699
try {
97100
const { userId } = req.query;
101+
const authenticatedUser = req.user;
98102

99-
const today = new Date();
103+
// Create today's date in IST timezone
104+
const now = new Date();
105+
const istOffset = 5.5 * 60 * 60 * 1000; // IST is UTC+5:30
106+
const istNow = new Date(now.getTime() + istOffset);
107+
108+
const today = new Date(istNow);
100109
today.setHours(0, 0, 0, 0);
101110
const tomorrow = new Date(today);
102111
tomorrow.setDate(tomorrow.getDate() + 1);
103112

113+
// Convert back to UTC for database query
114+
const todayUTC = new Date(today.getTime() - istOffset);
115+
const tomorrowUTC = new Date(tomorrow.getTime() - istOffset);
116+
104117
let dailyChallenge = await Challenge.findOne({
105118
createdAt: {
106-
$gte: today,
107-
$lt: tomorrow
119+
$gte: todayUTC,
120+
$lt: tomorrowUTC
108121
}
109-
}).sort({ createdAt: -1 }).select("-__v");
122+
}).sort({ createdAt: -1 });
110123

111124
if (!dailyChallenge) {
112-
dailyChallenge = await Challenge.findOne().sort({ createdAt: -1 }).select("-__v");
125+
dailyChallenge = await Challenge.findOne().sort({ createdAt: -1 });
113126
}
114127

115128
if (!dailyChallenge) {
116129
return res.status(404).json({ message: 'No daily challenge found' });
117130
}
118131

132+
let targetUser = null;
119133
let isSolved = false;
134+
120135
if (userId) {
121-
console.log(dailyChallenge.solvedUsers);
122-
isSolved = dailyChallenge.solvedUsers?.includes(userId) || false;
136+
try {
137+
targetUser = await User.findById(userId).select('solveChallenges _id');
138+
if (targetUser) {
139+
isSolved = dailyChallenge.solvedUsers?.includes(targetUser._id) || false;
140+
}
141+
} catch (error) {
142+
// Invalid user ID, continue without user context
143+
}
144+
} else if (authenticatedUser) {
145+
targetUser = authenticatedUser;
146+
isSolved = dailyChallenge.solvedUsers?.includes(authenticatedUser._id) || false;
123147
}
124148

125149
// Return challenge with solved status
@@ -210,4 +234,79 @@ export const getSolutionByChallengeId = async (req, res) => {
210234
} catch (error) {
211235
res.status(500).json({ message: 'Server error' });
212236
}
237+
};
238+
239+
240+
export const checkPOTDStatus = async (req, res) => {
241+
try {
242+
const { dailyChallengeId } = req.body;
243+
const user = req.user;
244+
const userId = req.user._id;
245+
246+
const dailyChallenge = await Challenge.findById(dailyChallengeId);
247+
if (!dailyChallenge) {
248+
return res.status(404).json({ message: 'Daily challenge not found', isSolved: false });
249+
}
250+
251+
let isSolved = dailyChallenge.solvedUsers?.includes(userId) || false;
252+
253+
if (isSolved) {
254+
return res.status(200).json({ message: "Daily challenge already solved", isSolved });
255+
}
256+
257+
let responseStatus;
258+
259+
if (dailyChallenge.platform === 'LeetCode') {
260+
responseStatus = await fetchLeetCodeStatus(user?.leetCode?.username, dailyChallenge.title);
261+
}
262+
263+
if (dailyChallenge.platform === 'Codeforces') {
264+
responseStatus = await fetchCodeforcesStatus(user?.codeforces?.username, dailyChallenge.title);
265+
}
266+
267+
if (responseStatus && responseStatus.success) {
268+
const now = new Intl.DateTimeFormat("en-IN", {
269+
timeZone: "Asia/Kolkata",
270+
year: "numeric",
271+
month: "2-digit",
272+
day: "2-digit",
273+
hour: "2-digit",
274+
minute: "2-digit",
275+
second: "2-digit",
276+
hour12: false,
277+
}).formatToParts(new Date());
278+
279+
let year = "", month = "", day = "", hour = "", minute = "", second = "";
280+
281+
now.forEach(part => {
282+
if (part.type === "year") year = part.value;
283+
if (part.type === "month") month = part.value;
284+
if (part.type === "day") day = part.value;
285+
if (part.type === "hour") hour = part.value;
286+
if (part.type === "minute") minute = part.value;
287+
if (part.type === "second") second = part.value;
288+
});
289+
290+
const timestamp = {
291+
date: `${year}-${month}-${day}`,
292+
time: `${hour}:${minute}:${second}`
293+
};
294+
295+
const postresponse = await postPotdChallenge(userId, timestamp, dailyChallengeId, dailyChallenge.difficulty);
296+
if (postresponse.success) {
297+
isSolved = true;
298+
return res.status(200).json({ message: "POTD challenge posted successfully", isSolved });
299+
} else {
300+
return res.status(400).json({ message: "Failed to post POTD challenge", isSolved: false });
301+
}
302+
} else {
303+
const platformName = dailyChallenge.platform;
304+
const errorMessage = responseStatus ? responseStatus.message : `Failed to fetch ${platformName} data`;
305+
return res.status(400).json({ message: errorMessage, isSolved: false });
306+
}
307+
308+
} catch (error) {
309+
console.error("Check POTD status error:", error);
310+
res.status(500).json({ message: 'Server error' });
311+
}
213312
};

server/controllers/platformsController.js

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -272,54 +272,11 @@ export const solvedChallenges = async (req, res) => {
272272
}
273273

274274

275-
export const fetchLeetCodeGraphql = async (req, res) => {
276-
const username = req.body.username;
275+
export const fetchLeetCodeStatus = async (username, challengeTitle) => {
277276
const query = `
278277
{
279278
matchedUser(username: "${username}") {
280279
username
281-
profile {
282-
realName
283-
userAvatar
284-
ranking
285-
reputation
286-
starRating
287-
aboutMe
288-
skillTags
289-
}
290-
submitStats: submitStatsGlobal {
291-
acSubmissionNum {
292-
difficulty
293-
count
294-
submissions
295-
}
296-
totalSubmissionNum {
297-
difficulty
298-
count
299-
submissions
300-
}
301-
}
302-
badges {
303-
id
304-
displayName
305-
icon
306-
creationDate
307-
}
308-
upcomingBadges {
309-
name
310-
icon
311-
}
312-
activeBadge {
313-
displayName
314-
icon
315-
}
316-
}
317-
userContestRanking(username: "${username}") {
318-
attendedContestsCount
319-
rating
320-
globalRanking
321-
totalParticipants
322-
topPercentage
323280
}
324281
recentSubmissionList(username: "${username}", limit: 20) {
325282
title
@@ -332,13 +289,62 @@ export const fetchLeetCodeGraphql = async (req, res) => {
332289
`;
333290
try {
334291
const response = await axios.post('https://leetcode.com/graphql', { query });
335-
return res.json(response.data.data);
292+
const { matchedUser, recentSubmissionList } = response.data.data;
293+
294+
if (!matchedUser) {
295+
throw new Error("Invalid LeetCode username");
296+
}
297+
298+
if (!recentSubmissionList || recentSubmissionList.length === 0) {
299+
throw new Error("No submissions found");
300+
}
301+
302+
const today = new Date().toLocaleDateString("en-IN", { timeZone: "Asia/Kolkata" }).split('/').reverse().join('-');
303+
304+
const solvedToday = recentSubmissionList.some(submission => {
305+
const submissionDate = new Date(parseInt(submission.timestamp) * 1000).toLocaleDateString("en-IN", { timeZone: "Asia/Kolkata" }).split('/').reverse().join('-');
306+
return submission.title === challengeTitle && submission.statusDisplay === "Accepted" && submissionDate === today;
307+
});
308+
309+
if (solvedToday) {
310+
return { success: true, message: "Challenge solved today" };
311+
} else {
312+
return { success: false, message: "Challenge not solved today" };
313+
}
314+
336315
} catch (error) {
337316
// console.error('Error fetching user data from LeetCode:', error);
338-
return null;
317+
return { success: false, message: "Failed to fetch LeetCode data" };
339318
}
340319
};
341320

321+
export const fetchCodeforcesStatus = async (username, challengeTitle) => {
322+
try {
323+
const response = await axios.get(`https://codeforces.com/api/user.status?handle=${username}&from=1&count=20`);
324+
const submissions = response.data;
325+
326+
if (!submissions || !submissions.result) {
327+
return { success: false, message: "Invalid Codeforces username or no submissions found" };
328+
}
329+
330+
const today = new Date().toLocaleDateString("en-IN", { timeZone: "Asia/Kolkata" }).split('/').reverse().join('-');
331+
332+
const solvedProblem = submissions.result.find((submission) => {
333+
const submissionDate = new Date(submission.creationTimeSeconds * 1000).toLocaleDateString("en-IN", { timeZone: "Asia/Kolkata" }).split('/').reverse().join('-');
334+
return submission.problem.name === challengeTitle && submission.verdict === "OK" && submissionDate === today;
335+
});
336+
337+
if (solvedProblem) {
338+
return { success: true, message: "Challenge solved today" };
339+
} else {
340+
return { success: false, message: "Challenge not solved today" };
341+
}
342+
343+
} catch (error) {
344+
console.error('Error fetching user data from Codeforces:', error);
345+
return { success: false, message: "Failed to fetch Codeforces data" };
346+
}
347+
}
342348

343349
export const heatmap = async (req, res) => {
344350
try {

0 commit comments

Comments
 (0)