Skip to content

Commit

Permalink
Remove cache upon new comment/like
Browse files Browse the repository at this point in the history
  • Loading branch information
tanish35 committed Oct 25, 2024
1 parent 2021ab8 commit 637fce0
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 15 deletions.
47 changes: 47 additions & 0 deletions backend/dist/controllers/postController.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const createPost = (0, express_async_handler_1.default)((req, res, next) => __aw
college_id: collegeId,
},
});
yield (0, redis_1.deleteCachedPosts)(collegeId);
return res.status(201).json({ post });
}));
exports.createPost = createPost;
Expand All @@ -133,6 +134,11 @@ const fetchPosts = (0, express_async_handler_1.default)((req, res) => __awaiter(
const pageNumber = page;
const postsPerPage = 4;
const offset = (pageNumber - 1) * postsPerPage;
const cacheKey = `posts:${collegeId || "all"}:page:${pageNumber}`;
const cachedResults = yield (0, redis_1.getCachedData)(cacheKey);
if (cachedResults) {
return res.status(200).json(JSON.parse(cachedResults));
}
const posts = yield prisma_1.default.post.findMany({
where: collegeId ? { college_id: collegeId } : {},
orderBy: {
Expand Down Expand Up @@ -165,6 +171,8 @@ const fetchPosts = (0, express_async_handler_1.default)((req, res) => __awaiter(
});
const totalPosts = yield prisma_1.default.post.count();
const isOver = offset + postsPerPage >= totalPosts;
const result = { posts, isOver };
yield (0, redis_1.setCachedData)(cacheKey, JSON.stringify(result), 600);
return res.status(200).json({ posts, isOver });
}));
exports.fetchPosts = fetchPosts;
Expand All @@ -176,6 +184,11 @@ const likePost = (0, express_async_handler_1.default)((req, res) => __awaiter(vo
where: { post_id: postId },
select: {
likes: true,
College: {
select: {
college_id: true,
},
},
},
});
// @ts-ignore
Expand Down Expand Up @@ -205,6 +218,7 @@ const likePost = (0, express_async_handler_1.default)((req, res) => __awaiter(vo
user_id,
},
});
yield (0, redis_1.deleteCachedPosts)(post.College.college_id);
return res.status(200).json({ updatedPost });
}));
exports.likePost = likePost;
Expand Down Expand Up @@ -262,6 +276,11 @@ const deletePost = (0, express_async_handler_1.default)((req, res) => __awaiter(
user_id: true,
},
},
College: {
select: {
college_id: true,
},
},
},
where: { post_id: postId },
});
Expand All @@ -285,6 +304,7 @@ const deletePost = (0, express_async_handler_1.default)((req, res) => __awaiter(
where: { post_id: postId },
});
}));
yield (0, redis_1.deleteCachedPosts)(post.College.college_id);
return res.status(200).json({ message: "Post and comments deleted" });
}));
exports.deletePost = deletePost;
Expand Down Expand Up @@ -319,6 +339,11 @@ const createComment = (0, express_async_handler_1.default)((req, res) => __await
user_id: true,
},
},
College: {
select: {
college_id: true,
},
},
},
});
if (!post) {
Expand Down Expand Up @@ -354,6 +379,7 @@ const createComment = (0, express_async_handler_1.default)((req, res) => __await
</div>
`;
(0, sendMail_1.default)(htmlContent, email, "New Comment on Your Post");
yield (0, redis_1.deleteCachedPosts)(post.College.college_id);
return res.status(201).json({ comment });
}));
exports.createComment = createComment;
Expand All @@ -367,6 +393,7 @@ const deleteComment = (0, express_async_handler_1.default)((req, res) => __await
user_id: true,
},
},
post_id: true,
},
where: { comment_id: commentId },
});
Expand All @@ -381,6 +408,20 @@ const deleteComment = (0, express_async_handler_1.default)((req, res) => __await
yield prisma_1.default.comment.delete({
where: { comment_id: commentId },
});
const collegeId = yield prisma_1.default.post.findUnique({
select: {
College: {
select: {
college_id: true,
},
},
},
where: { post_id: comment.post_id },
});
if (!collegeId) {
return res.status(404).json({ message: "College not found" });
}
yield (0, redis_1.deleteCachedPosts)(collegeId.College.college_id);
return res.status(200).json({ message: "Comment deleted" });
}));
exports.deleteComment = deleteComment;
Expand Down Expand Up @@ -416,6 +457,11 @@ const unlikePost = (0, express_async_handler_1.default)((req, res) => __awaiter(
where: { post_id: postId },
select: {
likes: true,
College: {
select: {
college_id: true,
},
},
},
});
if (!like) {
Expand All @@ -436,6 +482,7 @@ const unlikePost = (0, express_async_handler_1.default)((req, res) => __awaiter(
like_id: like.like_id,
},
});
yield (0, redis_1.deleteCachedPosts)(post.College.college_id);
return res.status(200).json({ updatedPost });
}));
exports.unlikePost = unlikePost;
Expand Down
6 changes: 5 additions & 1 deletion backend/dist/controllers/userControllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const sendMail_1 = __importDefault(require("../mail/sendMail"));
const academic_email_verifier_1 = require("academic-email-verifier");
const checkAcademic_1 = __importDefault(require("../mail/checkAcademic"));
const registerSchema_1 = require("../validation/registerSchema");
const redis_1 = __importDefault(require("../lib/redis"));
const googleSignInOrSignUp = (0, express_async_handler_1.default)(
//@ts-ignore
(req, res) => __awaiter(void 0, void 0, void 0, function* () {
Expand Down Expand Up @@ -260,7 +261,9 @@ const verifyUser = (0, express_async_handler_1.default)((req, res) => __awaiter(
const { sub, exp } = jsonwebtoken_1.default.verify(token, process.env.SECRET);
// @ts-ignore
if (exp < Date.now()) {
res.status(400).json({ message: "Token expired. Login to verify your email" });
res
.status(400)
.json({ message: "Token expired. Login to verify your email" });
return;
}
const user = yield prisma_1.default.user.findUnique({
Expand Down Expand Up @@ -629,6 +632,7 @@ const updateDetails = (0, express_async_handler_1.default)((req, res) => __await
pic,
},
});
yield redis_1.default.del(`user:${userId}`);
return res.status(200).json({ message: "Details updated" });
}));
exports.updateDetails = updateDetails;
30 changes: 29 additions & 1 deletion backend/dist/lib/redis.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.disconnectRedis = exports.setCachedData = exports.getCachedData = void 0;
exports.deleteCachedPosts = exports.disconnectRedis = exports.setCachedData = exports.getCachedData = void 0;
const ioredis_1 = __importDefault(require("ioredis"));
const redisURL = process.env.REDIS_URL;
if (!redisURL) {
Expand Down Expand Up @@ -47,4 +47,32 @@ const disconnectRedis = () => __awaiter(void 0, void 0, void 0, function* () {
}
});
exports.disconnectRedis = disconnectRedis;
const deleteCachedPosts = (collegeId) => __awaiter(void 0, void 0, void 0, function* () {
try {
const collegePattern = `posts:${collegeId}:page:*`;
const allPattern = `posts:all:page:*`;
const collegeStream = redis.scanStream({ match: collegePattern });
const allStream = redis.scanStream({ match: allPattern });
collegeStream.on("data", (keys) => {
if (keys.length) {
redis.del(...keys);
}
});
allStream.on("data", (keys) => {
if (keys.length) {
redis.del(...keys);
}
});
collegeStream.on("end", () => {
console.log(`Deleted cache for collegeId: ${collegeId}`);
});
allStream.on("end", () => {
console.log(`Deleted all cache entries.`);
});
}
catch (error) {
console.error("Error deleting cached posts from Redis", error);
}
});
exports.deleteCachedPosts = deleteCachedPosts;
exports.default = redis;
13 changes: 13 additions & 0 deletions backend/dist/middleware/checkAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const prisma_1 = __importDefault(require("../lib/prisma"));
const redis_1 = __importDefault(require("../lib/redis"));
// @ts-ignore
function requireAuth(req, res, next) {
return __awaiter(this, void 0, void 0, function* () {
Expand All @@ -26,6 +27,17 @@ function requireAuth(req, res, next) {
res.sendStatus(410);
return;
}
const userId = decoded.sub;
if (!userId) {
res.sendStatus(401);
return;
}
const cachedUser = yield redis_1.default.get(userId);
if (cachedUser) {
req.user = JSON.parse(cachedUser);
next();
return;
}
const user = yield prisma_1.default.user.findUnique({
where: {
user_id: decoded.sub,
Expand All @@ -36,6 +48,7 @@ function requireAuth(req, res, next) {
return;
}
req.user = user;
yield redis_1.default.set(`user:${userId}`, JSON.stringify(user), "EX", 3600);
next();
}
catch (err) {
Expand Down
46 changes: 46 additions & 0 deletions backend/dist/middleware/rateLimit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_async_handler_1 = __importDefault(require("express-async-handler"));
const ioredis_1 = __importDefault(require("ioredis"));
const redisUrl = process.env.REDIS_URL;
if (!redisUrl) {
throw new Error("REDIS_URL is not defined");
}
const redis = new ioredis_1.default(redisUrl);
const MAX_REQUESTS = 100;
const WINDOW_SIZE_IN_SECONDS = 60;
const rateLimiter = (0, express_async_handler_1.default)(
//@ts-ignore
(req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
//@ts-ignore
const clientIp = req.user.user_id;
// console.log(clientIp);
const key = `rate-limit:${clientIp}`;
const requestCount = yield redis.get(key);
if (requestCount && parseInt(requestCount) >= MAX_REQUESTS) {
return res
.status(429)
.json({ message: "Too many requests, please try again later." });
}
const ttl = yield redis.ttl(key);
if (ttl < 0) {
yield redis.set(key, 1, "EX", WINDOW_SIZE_IN_SECONDS);
}
else {
yield redis.incr(key);
}
next();
}));
exports.default = rateLimiter;
25 changes: 13 additions & 12 deletions backend/dist/routes/postsRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const postController_1 = require("../controllers/postController");
const checkAuth_1 = __importDefault(require("../middleware/checkAuth"));
const rateLimit_1 = __importDefault(require("../middleware/rateLimit"));
const postsRoutes = express_1.default.Router();
postsRoutes.get("/communities", checkAuth_1.default, postController_1.getCommunities);
postsRoutes.post("/create", checkAuth_1.default, postController_1.createPost);
postsRoutes.post("/fetch", checkAuth_1.default, postController_1.fetchPosts);
postsRoutes.post("/like", checkAuth_1.default, postController_1.likePost);
postsRoutes.get("/fetch/:id", checkAuth_1.default, postController_1.fetchSinglePost);
postsRoutes.post("/comment", checkAuth_1.default, postController_1.createComment);
postsRoutes.post("/liked", checkAuth_1.default, postController_1.postLiked);
postsRoutes.post("/unlike", checkAuth_1.default, postController_1.unlikePost);
postsRoutes.post("/search", checkAuth_1.default, postController_1.searchPosts);
postsRoutes.get("/allcommunities", checkAuth_1.default, postController_1.getAllCommunities);
postsRoutes.post("/deletecomment", checkAuth_1.default, postController_1.deleteComment);
postsRoutes.post("/deletepost", checkAuth_1.default, postController_1.deletePost);
postsRoutes.get("/communities", checkAuth_1.default, rateLimit_1.default, postController_1.getCommunities);
postsRoutes.post("/create", checkAuth_1.default, rateLimit_1.default, postController_1.createPost);
postsRoutes.post("/fetch", checkAuth_1.default, rateLimit_1.default, postController_1.fetchPosts);
postsRoutes.post("/like", checkAuth_1.default, rateLimit_1.default, postController_1.likePost);
postsRoutes.get("/fetch/:id", checkAuth_1.default, rateLimit_1.default, postController_1.fetchSinglePost);
postsRoutes.post("/comment", checkAuth_1.default, rateLimit_1.default, postController_1.createComment);
postsRoutes.post("/liked", checkAuth_1.default, rateLimit_1.default, postController_1.postLiked);
postsRoutes.post("/unlike", checkAuth_1.default, rateLimit_1.default, postController_1.unlikePost);
postsRoutes.post("/search", checkAuth_1.default, rateLimit_1.default, postController_1.searchPosts);
postsRoutes.get("/allcommunities", checkAuth_1.default, rateLimit_1.default, postController_1.getAllCommunities);
postsRoutes.post("/deletecomment", checkAuth_1.default, rateLimit_1.default, postController_1.deleteComment);
postsRoutes.post("/deletepost", checkAuth_1.default, rateLimit_1.default, postController_1.deletePost);
exports.default = postsRoutes;
3 changes: 2 additions & 1 deletion backend/dist/routes/userRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const userControllers_1 = require("../controllers/userControllers");
const checkAuth_1 = __importDefault(require("../middleware/checkAuth"));
const rateLimit_1 = __importDefault(require("../middleware/rateLimit"));
const router = express_1.default.Router();
router.route("/register").post(userControllers_1.registerUser);
router.route("/login").post(userControllers_1.loginUser);
Expand All @@ -19,5 +20,5 @@ router.post("/addDetails", userControllers_1.addDetailsToUser); // add details t
router.post("/addusername", userControllers_1.addUsername); // change the username of the current user
router.get("/all", userControllers_1.getAllUser);
router.get("/logout", userControllers_1.logOut);
router.post("/update", checkAuth_1.default, userControllers_1.updateDetails);
router.post("/update", checkAuth_1.default, rateLimit_1.default, userControllers_1.updateDetails);
exports.default = router;
Loading

0 comments on commit 637fce0

Please sign in to comment.