From 06ae17e6c66d1fabd2797a0b995ccb57090cb880 Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Mon, 1 Jun 2026 12:04:02 +0530 Subject: [PATCH 01/10] feat: add student history API endpoint --- package.json | 3 +- server.js | 79 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index f27df097..6160d11e 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "dev": "node ./server.js" + "start": "node index.js", + "dev": "nodemon index.js" }, "repository": { "type": "git", diff --git a/server.js b/server.js index ea2087f2..8b1ca667 100644 --- a/server.js +++ b/server.js @@ -1,37 +1,100 @@ const express = require("express"); const cors = require("cors"); -const path = require("path"); -const fs = require("fs"); + const app = express(); const PORT = process.env.PORT || 3000; app.use(cors()); -app.use(express.static(path.join(__dirname, "frontend"))); +app.use(express.static("frontend")); +/* ---------------- HOME ROUTES ---------------- */ app.get("/", (req, res) => { - res.sendFile(path.join(__dirname, "frontend", "index.html")); + res.sendFile(__dirname + "/frontend/index.html"); }); app.get("/leaderboard", (req, res) => { - res.sendFile(path.join(__dirname, "frontend", "leaderboard.html")); + res.sendFile(__dirname + "/frontend/leaderboard.html"); }); app.get("/about", (req, res) => { - res.sendFile(path.join(__dirname, "frontend", "about.html")); + res.sendFile(__dirname + "/frontend/about.html"); }); app.get("/registration", (req, res) => { - res.sendFile(path.join(__dirname, "frontend", "registration.html")); + res.sendFile(__dirname + "/frontend/registration.html"); }); app.get("/uptime", (req, res) => { res.json({ status: "Website is running ✅" }); }); +/* ---------------- API: STUDENT HISTORY ---------------- */ +app.get("/api/student/:username", async (req, res) => { + const { username } = req.params; + + try { + console.log("Fetching history for:", username); + + // 1. Get list of all daily files from GitHub repo + const apiURL = + "https://api.github.com/repos/codepvg/leetcode-ranking-data/contents/daily?ref=main"; + + const response = await fetch(apiURL); + const files = await response.json(); + + + if (!Array.isArray(files)) { + return res.status(500).json({ + error: "GitHub API failed", + details: files.message || files, + }); + } + + let history = []; + + // 2. Loop through each file + for (const file of files) { + if (!file.name.endsWith(".json")) continue; + + const fileRes = await fetch(file.download_url); + const data = await fileRes.json(); + + const user = data.find((u) => u.id === username); + + if (user) { + const date = file.name.split("-").slice(0, 3).join("-"); + + history.push({ + date, + easy: user.data.easySolved, + medium: user.data.mediumSolved, + hard: user.data.hardSolved, + }); + } + } + + // 3. Sort by date + history.sort((a, b) => new Date(a.date) - new Date(b.date)); + + res.json({ + username, + history, + }); + } catch (err) { + console.error(err); + res.status(500).json({ + error: "Failed to fetch student history", + details: err.message, + }); + } +}); + +/* ---------------- 404 ---------------- */ app.use((req, res) => { res.status(404).send("Page not found"); }); +/* ---------------- START ---------------- */ app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); -}); +}); \ No newline at end of file From 58e568e1f5eda9d7309dc09666248f40077727eb Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Mon, 1 Jun 2026 12:21:33 +0530 Subject: [PATCH 02/10] chore: update files --- .github/workflows/format-command.yml | 4 ++-- .github/workflows/prettier-check.yml | 6 +++--- .github/workflows/stale.yml | 10 +++++----- .github/workflows/sync-leaderboard.yml | 4 ++-- README.md | 21 +++++++++++---------- package.json | 4 ++-- server.js | 5 ++--- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/format-command.yml b/.github/workflows/format-command.yml index 60981ea6..d1235234 100644 --- a/.github/workflows/format-command.yml +++ b/.github/workflows/format-command.yml @@ -6,7 +6,7 @@ on: jobs: format: - name: 'Format code via comment' + name: "Format code via comment" runs-on: ubuntu-latest # Only run if it's a PR and the comment contains /format if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/format') @@ -48,7 +48,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: "20" - name: Run Prettier run: npx prettier --write "frontend/**/*.{html,css,js}" "scripts/**/*.js" "server.js" diff --git a/.github/workflows/prettier-check.yml b/.github/workflows/prettier-check.yml index 13688e84..488bbb5b 100644 --- a/.github/workflows/prettier-check.yml +++ b/.github/workflows/prettier-check.yml @@ -2,9 +2,9 @@ name: Prettier Check on: pull_request: - branches: [ main ] + branches: [main] push: - branches: [ main ] + branches: [main] jobs: prettier: @@ -22,7 +22,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: "20" - name: Run Prettier Requirements Check run: npx prettier --check "frontend/**/*.{html,css,js}" "scripts/**/*.js" "server.js" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 20296c6c..e66291dd 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,7 +2,7 @@ name: Mark stale issues and PRs on: schedule: - - cron: '0 0 * * *' + - cron: "0 0 * * *" jobs: stale: @@ -14,9 +14,9 @@ jobs: - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue has been inactive for 14 days and has been marked as stale. To keep this issue open, please leave a comment.' - stale-pr-message: 'This PR has been inactive for 14 days and has been marked as stale. If you are still working on it, please leave a comment.' - stale-issue-label: 'stale' - stale-pr-label: 'stale' + stale-issue-message: "This issue has been inactive for 14 days and has been marked as stale. To keep this issue open, please leave a comment." + stale-pr-message: "This PR has been inactive for 14 days and has been marked as stale. If you are still working on it, please leave a comment." + stale-issue-label: "stale" + stale-pr-label: "stale" days-before-stale: 14 days-before-close: 5 diff --git a/.github/workflows/sync-leaderboard.yml b/.github/workflows/sync-leaderboard.yml index 08622c2f..c2ca5952 100644 --- a/.github/workflows/sync-leaderboard.yml +++ b/.github/workflows/sync-leaderboard.yml @@ -2,7 +2,7 @@ name: Sync Leaderboard Data on: schedule: - - cron: '0 */3 * * *' + - cron: "0 */3 * * *" workflow_dispatch: concurrency: @@ -30,7 +30,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: "20" - name: Install dependencies run: npm install diff --git a/README.md b/README.md index 5bd6a63b..73d3ef6e 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ It allows users to register with their LeetCode username and automatically fetch The goal of this project is to: -- Encourage consistent problem-solving among students -- Create a competitive yet motivating environment -- Provide visibility into individual coding progress +- Encourage consistent problem-solving among students +- Create a competitive yet motivating environment +- Provide visibility into individual coding progress --- @@ -46,6 +46,7 @@ leetcode-ranking/ ### 1. Fork and clone the repository First, fork the repository to your GitHub account. Then clone it locally: + ```bash git clone https://github.com/YOUR-USERNAME/leetcode-ranking.git cd leetcode-ranking @@ -63,9 +64,9 @@ or ## Usage -1. Open the registration page -2. Enter your name and LeetCode username -3. Submit the form +1. Open the registration page +2. Enter your name and LeetCode username +3. Submit the form 4. View your ranking on the leaderboard after the next sync --- @@ -74,7 +75,7 @@ or Contributions are welcome. -- Fork the repository -- Create a new branch -- Make your changes -- Submit a Pull Request +- Fork the repository +- Create a new branch +- Make your changes +- Submit a Pull Request diff --git a/package.json b/package.json index 6160d11e..fb91ac52 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "start": "node index.js", - "dev": "nodemon index.js" + "start": "node index.js", + "dev": "nodemon index.js" }, "repository": { "type": "git", diff --git a/server.js b/server.js index 8b1ca667..2de5b401 100644 --- a/server.js +++ b/server.js @@ -37,12 +37,11 @@ app.get("/api/student/:username", async (req, res) => { // 1. Get list of all daily files from GitHub repo const apiURL = - "https://api.github.com/repos/codepvg/leetcode-ranking-data/contents/daily?ref=main"; + "https://api.github.com/repos/codepvg/leetcode-ranking-data/contents/daily?ref=main"; const response = await fetch(apiURL); const files = await response.json(); - if (!Array.isArray(files)) { return res.status(500).json({ error: "GitHub API failed", @@ -97,4 +96,4 @@ app.use((req, res) => { /* ---------------- START ---------------- */ app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); -}); \ No newline at end of file +}); From 3d9c27ae1f895164fc452bdf8280edcd660bf943 Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Wed, 3 Jun 2026 10:54:06 +0530 Subject: [PATCH 03/10] refactor: move student history logic to separate module --- scripts/fetch-student-history.js | 44 ++++++++++++++++++++++++++ server.js | 53 +++----------------------------- 2 files changed, 48 insertions(+), 49 deletions(-) create mode 100644 scripts/fetch-student-history.js diff --git a/scripts/fetch-student-history.js b/scripts/fetch-student-history.js new file mode 100644 index 00000000..93fffd3e --- /dev/null +++ b/scripts/fetch-student-history.js @@ -0,0 +1,44 @@ +async function fetchStudentHistory(username) { + console.log("Fetching history for:", username); + + const apiURL = + "https://api.github.com/repos/codepvg/leetcode-ranking-data/contents/daily?ref=main"; + + const response = await fetch(apiURL); + const files = await response.json(); + + if (!Array.isArray(files)) { + throw new Error(files.message || "GitHub API failed"); + } + + let history = []; + + for (const file of files) { + if (!file.name.endsWith(".json")) continue; + + const fileRes = await fetch(file.download_url); + const data = await fileRes.json(); + + const user = data.find((u) => u.id === username); + + if (user) { + const date = file.name.split("-").slice(0, 3).join("-"); + + history.push({ + date, + easy: user.data.easySolved, + medium: user.data.mediumSolved, + hard: user.data.hardSolved, + }); + } + } + + history.sort((a, b) => new Date(a.date) - new Date(b.date)); + + return { + username, + history, + }; +} + +module.exports = fetchStudentHistory; \ No newline at end of file diff --git a/server.js b/server.js index 2de5b401..ea898d1c 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,8 @@ const cors = require("cors"); const app = express(); const PORT = process.env.PORT || 3000; +const fetchStudentHistory = require("./scripts/fetch-student-history"); + app.use(cors()); app.use(express.static("frontend")); @@ -30,57 +32,10 @@ app.get("/uptime", (req, res) => { /* ---------------- API: STUDENT HISTORY ---------------- */ app.get("/api/student/:username", async (req, res) => { - const { username } = req.params; - try { - console.log("Fetching history for:", username); - - // 1. Get list of all daily files from GitHub repo - const apiURL = - "https://api.github.com/repos/codepvg/leetcode-ranking-data/contents/daily?ref=main"; - - const response = await fetch(apiURL); - const files = await response.json(); - - if (!Array.isArray(files)) { - return res.status(500).json({ - error: "GitHub API failed", - details: files.message || files, - }); - } - - let history = []; - - // 2. Loop through each file - for (const file of files) { - if (!file.name.endsWith(".json")) continue; - - const fileRes = await fetch(file.download_url); - const data = await fileRes.json(); - - const user = data.find((u) => u.id === username); - - if (user) { - const date = file.name.split("-").slice(0, 3).join("-"); - - history.push({ - date, - easy: user.data.easySolved, - medium: user.data.mediumSolved, - hard: user.data.hardSolved, - }); - } - } - - // 3. Sort by date - history.sort((a, b) => new Date(a.date) - new Date(b.date)); - - res.json({ - username, - history, - }); + const data = await fetchStudentHistory(req.params.username); + res.json(data); } catch (err) { - console.error(err); res.status(500).json({ error: "Failed to fetch student history", details: err.message, From c0ea29d0f836b9b964e5037c6b97e95e8993f1a7 Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Wed, 3 Jun 2026 10:59:01 +0530 Subject: [PATCH 04/10] style: format student history module --- scripts/fetch-student-history.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fetch-student-history.js b/scripts/fetch-student-history.js index 93fffd3e..85f00c48 100644 --- a/scripts/fetch-student-history.js +++ b/scripts/fetch-student-history.js @@ -41,4 +41,4 @@ async function fetchStudentHistory(username) { }; } -module.exports = fetchStudentHistory; \ No newline at end of file +module.exports = fetchStudentHistory; From c9f2896176d3b21e77e4d92131f670ace5865d9a Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Wed, 3 Jun 2026 20:13:26 +0530 Subject: [PATCH 05/10] changing the file name and removing comments --- ...{fetch-student-history.js => fetch-student-info.js} | 0 server.js | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) rename scripts/{fetch-student-history.js => fetch-student-info.js} (100%) diff --git a/scripts/fetch-student-history.js b/scripts/fetch-student-info.js similarity index 100% rename from scripts/fetch-student-history.js rename to scripts/fetch-student-info.js diff --git a/server.js b/server.js index ea898d1c..10405ac0 100644 --- a/server.js +++ b/server.js @@ -3,8 +3,9 @@ const cors = require("cors"); const app = express(); const PORT = process.env.PORT || 3000; +const path = require("path"); -const fetchStudentHistory = require("./scripts/fetch-student-history"); +const fetchStudentHistory = require("./scripts/fetch-student-info"); app.use(cors()); app.use(express.static("frontend")); @@ -30,25 +31,24 @@ app.get("/uptime", (req, res) => { res.json({ status: "Website is running ✅" }); }); -/* ---------------- API: STUDENT HISTORY ---------------- */ + app.get("/api/student/:username", async (req, res) => { try { const data = await fetchStudentHistory(req.params.username); res.json(data); } catch (err) { res.status(500).json({ - error: "Failed to fetch student history", + error: "Failed to fetch student details", details: err.message, }); } }); -/* ---------------- 404 ---------------- */ app.use((req, res) => { res.status(404).send("Page not found"); }); -/* ---------------- START ---------------- */ + app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); }); From 78fbf351a6886153e33f6b35bffbb7bfe7cd6667 Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Wed, 3 Jun 2026 20:34:14 +0530 Subject: [PATCH 06/10] style: apply prettier formatting --- CODE_OF_CONDUCT.md | 23 +++++++++++------------ README.md | 7 ++----- server.js | 2 -- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9767a1e2..1307ce7b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within @@ -126,4 +126,3 @@ enforcement ladder](https://github.com/mozilla/diversity). For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. - diff --git a/README.md b/README.md index f5560a08..ff3f1186 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ The goal of this project is to: --- - - ## Screenshots + A quick preview of the platform UI. The appearance may evolve as the project develops. + ### Home Page ![Home Page](assets/home-page.png) @@ -28,13 +28,10 @@ A quick preview of the platform UI. The appearance may evolve as the project dev ![Registration](assets/registration-page.png) - ### Leaderboard ![Leaderboard](assets/leaderboard.png) - - ## Related Repositories - [leetcode-ranking-data](https://github.com/codepvg/leetcode-ranking-data) – The database repository where raw JSON data and historical stats are stored diff --git a/server.js b/server.js index 10405ac0..8ef52c71 100644 --- a/server.js +++ b/server.js @@ -31,7 +31,6 @@ app.get("/uptime", (req, res) => { res.json({ status: "Website is running ✅" }); }); - app.get("/api/student/:username", async (req, res) => { try { const data = await fetchStudentHistory(req.params.username); @@ -48,7 +47,6 @@ app.use((req, res) => { res.status(404).send("Page not found"); }); - app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); }); From 571827199933810fdd4711490396abc5ed00ccac Mon Sep 17 00:00:00 2001 From: Yashaswini K P Date: Wed, 3 Jun 2026 20:47:10 +0530 Subject: [PATCH 07/10] message --- server.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 8ef52c71..5c78ee92 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,30 @@ const express = require("express"); const cors = require("cors"); +const path = require("path"); const app = express(); const PORT = process.env.PORT || 3000; -const path = require("path"); const fetchStudentHistory = require("./scripts/fetch-student-info"); app.use(cors()); -app.use(express.static("frontend")); +app.use(express.static(path.join(__dirname, "frontend"))); /* ---------------- HOME ROUTES ---------------- */ app.get("/", (req, res) => { - res.sendFile(__dirname + "/frontend/index.html"); + res.sendFile(path.join(__dirname, "frontend", "index.html")); }); app.get("/leaderboard", (req, res) => { - res.sendFile(__dirname + "/frontend/leaderboard.html"); + res.sendFile(path.join(__dirname, "frontend", "leaderboard.html")); }); app.get("/about", (req, res) => { - res.sendFile(__dirname + "/frontend/about.html"); + res.sendFile(path.join(__dirname, "frontend", "about.html")); }); app.get("/registration", (req, res) => { - res.sendFile(__dirname + "/frontend/registration.html"); + res.sendFile(path.join(__dirname, "frontend", "registration.html")); }); app.get("/uptime", (req, res) => { From 25154e75484e427530ce91368f75d91c685b0e95 Mon Sep 17 00:00:00 2001 From: Jagdish Prajapati Date: Wed, 3 Jun 2026 22:48:22 +0530 Subject: [PATCH 08/10] improve user history API response time --- scripts/fetch-student-info.js | 87 ++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/scripts/fetch-student-info.js b/scripts/fetch-student-info.js index 85f00c48..4eee1465 100644 --- a/scripts/fetch-student-info.js +++ b/scripts/fetch-student-info.js @@ -1,35 +1,80 @@ +function getFileName(daysAgo) { + const now = new Date(); + now.setDate(now.getDate() - daysAgo); + + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, "0"); + const date = String(now.getDate()).padStart(2, "0"); + let day = now.getDay(); + day = day === 0 ? 7 : day; + + return `${year}-${month}-${date}-${day}.json`; +} + async function fetchStudentHistory(username) { console.log("Fetching history for:", username); - const apiURL = - "https://api.github.com/repos/codepvg/leetcode-ranking-data/contents/daily?ref=main"; + let history = []; + let missingFilesCount = 0; + const maxDays = 365; + const chunkSize = 100; - const response = await fetch(apiURL); - const files = await response.json(); + let done = false; - if (!Array.isArray(files)) { - throw new Error(files.message || "GitHub API failed"); - } + for (let chunkStart = 0; chunkStart < maxDays; chunkStart += chunkSize) { + if (done) break; - let history = []; + const fetchPromises = []; + const chunkEnd = Math.min(chunkStart + chunkSize, maxDays); + + for (let daysAgo = chunkStart; daysAgo < chunkEnd; daysAgo++) { + const fileName = getFileName(daysAgo); + const rawUrl = `https://raw.githubusercontent.com/codepvg/leetcode-ranking-data/main/daily/${fileName}`; + + const p = fetch(rawUrl) + .then(async (res) => { + if (!res.ok) { + return { daysAgo, fileName, ok: false }; + } + const data = await res.json(); + return { daysAgo, fileName, ok: true, data }; + }) + .catch((err) => { + return { daysAgo, fileName, ok: false, error: err }; + }); + + fetchPromises.push(p); + } + + const results = await Promise.all(fetchPromises); - for (const file of files) { - if (!file.name.endsWith(".json")) continue; + for (const result of results) { + if (!result.ok) { + missingFilesCount++; + if (missingFilesCount >= 7) { + done = true; + break; + } + continue; + } - const fileRes = await fetch(file.download_url); - const data = await fileRes.json(); + missingFilesCount = 0; - const user = data.find((u) => u.id === username); + const user = result.data.find((u) => u.id === username); - if (user) { - const date = file.name.split("-").slice(0, 3).join("-"); + if (user) { + const dateStr = result.fileName.split("-").slice(0, 3).join("-"); - history.push({ - date, - easy: user.data.easySolved, - medium: user.data.mediumSolved, - hard: user.data.hardSolved, - }); + history.push({ + date: dateStr, + easy: user.data.easySolved, + medium: user.data.mediumSolved, + hard: user.data.hardSolved, + }); + } else { + done = true; + break; + } } } From 943ef4494f117f48c0ecbe51938bfa2160c9b0c6 Mon Sep 17 00:00:00 2001 From: Jagdish Prajapati Date: Wed, 3 Jun 2026 22:56:42 +0530 Subject: [PATCH 09/10] Change main entry point from index.js to server.js --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 23078d0f..25079eb8 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,10 @@ "name": "leetcode-ranking", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "server.js", "scripts": { - "start": "node index.js", - "dev": "nodemon index.js" + "start": "node server.js", + "dev": "nodemon server.js" }, "repository": { "type": "git", From db5465e5a2028ec67fb5b543736ac39c584d9576 Mon Sep 17 00:00:00 2001 From: Jagdish Prajapati Date: Wed, 3 Jun 2026 23:04:32 +0530 Subject: [PATCH 10/10] Add caching for student API endpoint Implement caching for student data retrieval to improve performance. --- server.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 5c78ee92..298ff019 100644 --- a/server.js +++ b/server.js @@ -31,9 +31,23 @@ app.get("/uptime", (req, res) => { res.json({ status: "Website is running ✅" }); }); +const studentCache = new Map(); + app.get("/api/student/:username", async (req, res) => { + const username = req.params.username; + + if (studentCache.has(username)) { + const cached = studentCache.get(username); + if (Date.now() - cached.timestamp < 5 * 60 * 1000) { + return res.json(cached.data); + } + } + try { - const data = await fetchStudentHistory(req.params.username); + const data = await fetchStudentHistory(username); + + studentCache.set(username, { timestamp: Date.now(), data }); + res.json(data); } catch (err) { res.status(500).json({