Skip to content

Commit a6f0e53

Browse files
committed
feat: Implement caching for global stats and enhance user authentication with caching
1 parent f7eca1d commit a6f0e53

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

server/controllers/statsControllers.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { User } from "../models/User.js";
22
import { Challenge } from "../models/Challenge.js";
33
import auditService from "../services/auditService.js";
4+
import cacheService from "../services/cacheService.js";
5+
6+
const CACHE_NAMESPACE = 'stats';
7+
const STATS_TTL = 600;
48

59
const formatCount = (num) => {
610
if (num >= 1_000_000) return (num / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M+";
@@ -11,6 +15,11 @@ const formatCount = (num) => {
1115

1216
export const getCounts = async (req, res) => {
1317
try {
18+
const cachedStats = await cacheService.get(CACHE_NAMESPACE, 'global_stats');
19+
if (cachedStats) {
20+
return res.status(200).json(cachedStats);
21+
}
22+
1423
const usersCount = await User.countDocuments();
1524
const challengesCount = await Challenge.countDocuments();
1625
const collegesCount = await User.distinct("college").then(colleges => colleges.length);
@@ -19,7 +28,7 @@ export const getCounts = async (req, res) => {
1928
solvedUsers: { $exists: true, $not: { $size: 0 } }
2029
});
2130

22-
// 🔹 Count challenges by difficulty (Easy, Medium, Hard)
31+
// Challenges count by difficulty (Easy, Medium, Hard)
2332
const difficulties = await Challenge.aggregate([
2433
{
2534
$group: {
@@ -38,7 +47,7 @@ export const getCounts = async (req, res) => {
3847
}
3948
]);
4049

41-
// 🔹 Format difficulty data into a consistent structure
50+
// Format difficulty data into a consistent structure
4251
const difficultyMap = { Easy: 0, Medium: 0, Hard: 0 };
4352
difficulties.forEach(d => {
4453
if (difficultyMap[d._id] !== undefined) {
@@ -52,15 +61,19 @@ export const getCounts = async (req, res) => {
5261
{ name: "Hard", value: difficultyMap.Hard, color: "#ef4444" }
5362
];
5463

55-
// 🔹 Send all counts + difficulty data
56-
res.status(200).json({
64+
// Prepare stats object
65+
const statsData = {
5766
usersCount: formatCount(usersCount),
5867
challengesCount: formatCount(challengesCount),
5968
collegesCount: formatCount(collegesCount),
6069
affiliatesCount: formatCount(affiliatesCount),
6170
solvedChallenges: formatCount(solvedChallenges),
6271
difficultyDistribution: difficultyData
63-
});
72+
};
73+
74+
await cacheService.set(CACHE_NAMESPACE, 'global_stats', statsData, STATS_TTL);
75+
76+
res.status(200).json(statsData);
6477
} catch (error) {
6578
auditService.error("Get stats counts failed", error, {
6679
requestId: req.auditContext?.requestId

server/middleware/auth.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import jwt from "jsonwebtoken";
22
import { User } from "../models/User.js";
33
import passport from "../config/passport.js";
4+
import userCacheService from "../services/userCacheService.js";
45

56
export const protect = async (req, res, next) => {
67
let token;
@@ -9,8 +10,6 @@ export const protect = async (req, res, next) => {
910

1011
token = req.cookies.jwt;
1112

12-
// console.log("Token from cookies:", token);
13-
1413
if(!token) {
1514
token = req.headers.authorization?.split(" ")[1];
1615
// if(token) console.log("Token from headers:", token);
@@ -21,14 +20,21 @@ export const protect = async (req, res, next) => {
2120
}
2221

2322
const decoded = jwt.verify(token, process.env.JWT_SECRET);
24-
// console.log("Decoded token:", decoded.id);
23+
let user = await userCacheService.getCachedUserProfile(decoded.id);
24+
25+
if (!user) {
26+
user = await User.findById(decoded.id).select('-password -gfg -codechef -otp -otpExpires -createdAt -updatedAt -resetPasswordToken -resetPasswordExpires -googleId -githubId');
2527

26-
req.user = await User.findById(decoded.id).select('-password -gfg -codechef -otp -otpExpires -createdAt -updatedAt -resetPasswordToken -resetPasswordExpires -googleId -githubId'); // Exclude sensitive fields
28+
if (user) {
29+
await userCacheService.cacheUserProfile(decoded.id, user);
30+
}
31+
}
2732

28-
if (!req.user) {
33+
if (!user) {
2934
return res.status(401).json({ message: 'Not authorized, token failed' });
3035
}
3136

37+
req.user = user;
3238
req.token = token;
3339

3440
next();

0 commit comments

Comments
 (0)