From 9dc973658ad7f4d153d71ad3a433d95bdddfd9ed Mon Sep 17 00:00:00 2001 From: Rituraj Singh <2300520140055@ietlucknow.ac.in> Date: Sun, 25 Aug 2024 03:06:17 +0530 Subject: [PATCH] leetcode --- backend/package-lock.json | 39 +++++++++ backend/src/controller/search.js | 126 ++++++++++++++++++++++----- backend/src/controller/user.js | 10 +++ frontend/src/components/LeetCode.jsx | 46 +++------- frontend/src/pages/Settings.jsx | 24 ++--- 5 files changed, 174 insertions(+), 71 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 52c4867..fa9e417 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -25,6 +25,7 @@ "express": "^4.19.2", "express-rate-limit": "^7.4.0", "jsonwebtoken": "^9.0.2", + "leetcode-query": "^1.2.3", "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.13", "puppeteer": "^23.1.0", @@ -344,6 +345,20 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, + "node_modules/@fetch-impl/cross-fetch": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@fetch-impl/cross-fetch/-/cross-fetch-1.0.0.tgz", + "integrity": "sha512-vNvwtCQ7yruvpYnp1i/4paVi/icrGYx9O4eHNDYorjTAFg78bhitO0l39opJSVfsTKqyWqj3+2+YenoGhZOCJA==", + "peerDependencies": { + "@fetch-impl/fetcher": "^1.0.0", + "cross-fetch": "*" + } + }, + "node_modules/@fetch-impl/fetcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@fetch-impl/fetcher/-/fetcher-1.0.0.tgz", + "integrity": "sha512-UPUN9Yfjnk513Vc08iNW8/9L1nSwQMsTx6nOvmjPNfU2Rtbew/2KgAbQDPuoL6PrNgEmEmmyeM29BkcVBpt3gQ==" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -1367,6 +1382,14 @@ } } }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -1631,6 +1654,11 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, "node_modules/express": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", @@ -2360,6 +2388,17 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/leetcode-query": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/leetcode-query/-/leetcode-query-1.2.3.tgz", + "integrity": "sha512-J73ehmjgIfDd3Ugg1ee83bDALNaGh78nQwDS5qyPOsgGahK55a2lcl9Q/iaByKi6AUMMxsHEyEsUNGBX4Lmn2Q==", + "dependencies": { + "@fetch-impl/cross-fetch": "^1.0.0", + "@fetch-impl/fetcher": "^1.0.0", + "cross-fetch": "^4.0.0", + "eventemitter3": "^5.0.1" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", diff --git a/backend/src/controller/search.js b/backend/src/controller/search.js index 6529336..42b803c 100644 --- a/backend/src/controller/search.js +++ b/backend/src/controller/search.js @@ -1,6 +1,7 @@ import prisma from "../../db/db.config.js"; import CryptoJS from "crypto-js"; - +import axios from "axios"; +import { LeetCode } from "leetcode-query"; export const getUsers = async (req, res) => { try { @@ -23,7 +24,7 @@ export const getUsers = async (req, res) => { take: limit, }); - let rooms= await prisma.rooms.findMany({ + let rooms = await prisma.rooms.findMany({ where: { title: { contains: key, @@ -37,10 +38,9 @@ export const getUsers = async (req, res) => { }, take: limit, }); - res.status(200).send({users, rooms }); + res.status(200).send({ users, rooms }); } catch (error) { console.log(error); - } }; @@ -197,29 +197,113 @@ export const getUserUpvotes = async (req, res) => { }; export const getLCdata = async (req, res) => { + const encryptUsername = req.body.username; + + try { + const bytes = CryptoJS.AES.decrypt( + encryptUsername, + process.env.LC_SECRETKEY + ); + const username = bytes.toString(CryptoJS.enc.Utf8); + console.log("LC_username", username); + + const data =await getLeetCodeData(username); + + + const user = data.matchedUser; + + if (!user) { + res.status(404).send({ status: "error" }); + } + + const solved = user.submitStats.acSubmissionNum; + + const totalSolved = solved[0].count; + const easySolved = solved[1].count; + const mediumSolved = solved[2].count; + const hardSolved = solved[3].count; + + const succSubmission = solved[0].submissions; + const totalSubmission = user.submitStats.totalSubmissionNum[0].submissions; + const acceptanceRate = ((succSubmission / totalSubmission) * 100).toFixed( + 2 + ); + + const contributionPoints = user.contributions.points; + const ranking = user.profile.ranking; + const allQuestions = data.allQuestionsCount; - const encryptUsername = req.body.username; - console.log(encryptUsername); + const totalQuestions = allQuestions[0].count; + const totalEasy = allQuestions[1].count; + const totalMedium = allQuestions[2].count; + const totalHard = allQuestions[3].count; - + res.status(200).send({ + ranking, + totalQuestions, + totalEasy, + totalMedium, + totalHard, + easySolved, + mediumSolved, + hardSolved, + totalSolved, + acceptanceRate, + contributionPoints, + }); + } catch (error) { + console.log(error); + } +}; + +export const getLeetCodeData = async (username) => { try { - + const query = ` + { + allQuestionsCount { + difficulty + count + } + matchedUser(username: "${username}") { + + submitStats { + acSubmissionNum { + difficulty + count + submissions + } + totalSubmissionNum { + difficulty + count + submissions + } + } + contributions{ + points + questionCount + testcaseCount + } + profile { + ranking + reputation + } + + } - const bytes = CryptoJS.AES.decrypt(encryptUsername, process.env.LC_SECRETKEY); - const username = bytes.toString(CryptoJS.enc.Utf8); - console.log("username", username); - console.log("sk", process.env.LC_SECRETKEY); - - - - let data = await fetch( - `https://leetcode-stats-api.herokuapp.com/${username}` + }`; + + const response = await axios.post( + "https://leetcode.com/graphql", + { query }, + { + headers: { + "Content-Type": "application/json", + }, + } ); - let result = await data.json(); - console.log(result); - - res.status(202).send(result); + let data = response.data.data; + return data; } catch (error) { console.log(error); } diff --git a/backend/src/controller/user.js b/backend/src/controller/user.js index bb85817..82ba10f 100644 --- a/backend/src/controller/user.js +++ b/backend/src/controller/user.js @@ -2,6 +2,7 @@ import prisma from "../../db/db.config.js"; import jwt from "jsonwebtoken"; import bcrypt from "bcrypt"; import uploadOnCloudinary from "../utils/cloudinary.js"; +import { getLeetCodeData } from "./search.js"; const getUser = async (req, res) => { const email = req.params?.email; @@ -237,6 +238,15 @@ const addLC = async (req, res) => { const {lcusername}= req.body; try { + const lcdata= await getLeetCodeData(lcusername); + console.log(lcdata); + + const user= lcdata.matchedUser + if(!user){ + res.status(404).send("user not found!"); + return + } + const data= await prisma.user.update({ where:{ userID, diff --git a/frontend/src/components/LeetCode.jsx b/frontend/src/components/LeetCode.jsx index becb181..1c78b0f 100644 --- a/frontend/src/components/LeetCode.jsx +++ b/frontend/src/components/LeetCode.jsx @@ -3,8 +3,8 @@ import { CircularProgressbar, buildStyles } from 'react-circular-progressbar'; import 'react-circular-progressbar/dist/styles.css'; import Greencheck from '../assets/Greencheck'; import { useSelector } from 'react-redux'; -import { SlBadge } from "react-icons/sl"; -import { FaRankingStar } from "react-icons/fa6"; +import toast from 'react-hot-toast'; + import { FaTrophy } from "react-icons/fa" import { SiLeetcode } from 'react-icons/si'; import { LeetCodeSkelton } from './Postskelton'; @@ -23,20 +23,6 @@ const LeetCode = () => { const [isLoading, setisLoading] = useState(false) - const keysToKeep = [ - "acceptanceRate", - "contributionPoints", - "easySolved", - "hardSolved", - "mediumSolved", - "ranking", - "totalEasy", - "totalHard", - "totalMedium", - "totalQuestions", - "totalSolved" - ]; - const { acceptanceRate, contributionPoints, @@ -71,21 +57,14 @@ const LeetCode = () => { let res = await axios.post(`${baseAddress}search/getLCdata/`, {username: encUsername}); - - if (res.data.status == "success") { - const lcdata = Object.keys(res.data) - .filter(key => keysToKeep.includes(key)) - .reduce((obj, key) => { - obj[key] = res.data[key]; - return obj; - }, {}); - - setlcdata(lcdata); + if (res.status==200) { + + setlcdata(res.data); } else { - console.log("User Not Found"); - seterror("Invalid Username!") + console.log("Some error occured!"); + toast.error("Some error occured!") } @@ -157,7 +136,7 @@ const LeetCode = () => { -