From 1490bb7a5d6d601257f179a83a452183a5945405 Mon Sep 17 00:00:00 2001 From: ABHINAVGARG05 Date: Sun, 16 Feb 2025 15:58:41 +0530 Subject: [PATCH 1/2] updated controllers --- .env => .env.example | 2 +- .gitignore | 2 +- controllers/authController.js | 230 +++++++++++++++--------------- controllers/questionController.js | 52 ++++--- controllers/userController.js | 118 ++++++--------- index.js | 2 + 6 files changed, 204 insertions(+), 202 deletions(-) rename .env => .env.example (67%) diff --git a/.env b/.env.example similarity index 67% rename from .env rename to .env.example index 29ffcca..00f8c3f 100644 --- a/.env +++ b/.env.example @@ -1,4 +1,4 @@ PORT =5001 CONNECT_STRING= Enter your DB url -ACCESS_TOKEN_SECERT = SOTYBackendHarshitPG +ACCESS_TOKEN_SECERT= SOTYBackendHarshitPG REFRESH_TOKEN_SECERT= SOTYBackendHarshitPG diff --git a/.gitignore b/.gitignore index 208d50c..c6bba59 100644 --- a/.gitignore +++ b/.gitignore @@ -73,7 +73,7 @@ web_modules/ .yarn-integrity # dotenv environment variable files -# .env +.env .env.development.local .env.test.local .env.production.local diff --git a/controllers/authController.js b/controllers/authController.js index 9329392..8b9e667 100644 --- a/controllers/authController.js +++ b/controllers/authController.js @@ -1,150 +1,154 @@ const UserModel = require("../models/userModel"); const jwt = require("jsonwebtoken"); const bcrypt = require("bcrypt"); -const crypto = require("crypto"); +require("dotenv").config(); -//Registering a new user +const generateAccessToken = (user) => { + return jwt.sign( + { username: user.username, id: user._id, teamname: user.teamname }, + process.env.ACCESS_TOKEN_SECRET, + { + expiresIn: process.env.ACCESS_TOKEN_EXPIRY || "45m" + } + ); +}; -const registerUser = async (req, res) => { - const { username, teamname, password, score } = req.body; - console.log(req.body); +const generateRefreshToken = (user) => { + return jwt.sign( + { username: user.username, id: user._id }, + process.env.REFRESH_TOKEN_SECRET, + { + expiresIn: process.env.REFRESH_TOKEN_EXPIRY || "7d" + } + ); +}; +const registerUser = async (req, res) => { try { - const userAvailable = await UserModel.findOne({ username }); - if (userAvailable) { - return res.status(400).json({ message: "User already exists" }); + const { username, teamname, password, score } = req.body; + + if (!username || !teamname || !password) { + return res.status(400).json( + { + message: "All fields are required" + } + ); + } + + const userExists = await UserModel.findOne({ username }); + if (userExists) { + return res.status(400).json( + { + message: "User already exists" + } + ); } - const salt = await bcrypt.genSalt(10); - const hashedPassword = await bcrypt.hash(password, salt); - console.log("Hashed Password: ", hashedPassword); + + const hashedPassword = await bcrypt.hash(password, 10); + const newUser = new UserModel({ - username: username, - teamname: teamname, + username, + teamname, password: hashedPassword, - score: score, - // refreshToken: [], + score: score || 0, }); - const user = await newUser.save(); - const token = jwt.sign( - { username: user.username, id: user._id, teamname: user.teamname }, - process.env.ACCESS_TOKEN_SECERT, - { expiresIn: "45m" } - ); + const user = await newUser.save(); + const token = generateAccessToken(user); - console.log(`User created ${user}`); - console.log(`User token ${token}`); - res.status(200).json({ user }); + console.log(`User registered: ${user}`); + res.status(201).json({ user, token }); } catch (error) { - res.status(500).json({ message: error.message }); + console.error(error); + res.status(500).json({ message: "Internal server error" }); } }; -//login User - const loginUser = async (req, res) => { - const { username, password } = req.body; try { - const user = await UserModel.findOne({ - username: username, - }); + const { username, password } = req.body; + if (!username || !password) { + return res.status(400).json( + { + message: "Username and password required" + } + ); + } - if (user) { - // if (user.isBan) { - // const TimeOut = 120 * 60 * 1000; - - // const timeElapsed = Date.now() - user.banTime; - - // if (timeElapsed < TimeOut) { - // const remainingTime = TimeOut - timeElapsed; - // await UserModel.findByIdAndUpdate(req.params.id, { isBan: true }); - // return res.status(403).json({ - // message: `User has banned. Please wait for ${remainingTime} milliseconds.`, - // remainingTime: remainingTime, - // isBan: user.isBan, - // }); - // } - // } - const validity = await bcrypt.compare(password, user.password); - if (!validity) { - res.send(400).json("Wrong password"); - } else { - const token = jwt.sign( - { username: user.username, id: user._id, isAdmin: user.isAdmin }, - process.env.ACCESS_TOKEN_SECERT, - { expiresIn: "1d" } - ); + const user = await UserModel.findOne({ username }); + if (!user) { + return res.status(404).json( + { + message: "User not found" + } + ); + } - const refreshToken = generateRefreshToken(user); - user.refreshToken = refreshToken; + const isValidPassword = await bcrypt.compare(password, user.password); + if (!isValidPassword) { + return res.status(400).json( + { + message: "Incorrect password" + } + ); + } - user.prevAccessToken = user.accessTokens; - user.accessTokens = []; - await user.save(); + const accessToken = generateAccessToken(user); + const refreshToken = generateRefreshToken(user); - user.accessTokens.push(token); - await user.save(); + user.refreshToken = refreshToken; + await user.save(); - console.log(`User created login : ${user}`); - console.log(`User token login: ${token}`); - res.status(200).json({ user, token, refreshToken }); - } - } else { - res.status(404).json("User not found"); - } + console.log(`User logged in: ${user.username}`); + res.status(200).json({ user, accessToken, refreshToken }); } catch (error) { - res.status(500).json(error.message); + console.error(error); + res.status(500).json( + { + message: "Internal server error" + } + ); } }; -//refreshToken const refreshToken = async (req, res) => { - const { refreshToken } = req.body; - let token; - let authHeader = req.headers.authorization || req.headers.Authorization; - - if (!authHeader || !authHeader.startsWith("Bearer")) { - return res - .status(401) - .json({ message: "User is not authorized or token missing" }); - } - - token = authHeader.split(" ")[1]; - - if (!refreshToken) { - return res.status(400).json({ message: "refreshToken is required." }); - } try { - const user = await UserModel.findOne({ refreshToken: refreshToken }); - console.log("user refresh:", user); - if (!user) { - return res.status(404).json({ message: "Invalid refreshToken" }); + const { refreshToken } = req.body; + if (!refreshToken) { + return res.status(400).json( + { + message: "Refresh token required" + } + ); } - const storeRefeshToken = user.refreshToken; - if (!storeRefeshToken) { - return res.status(400).json({ message: "Invalid refrsh token" }); + + const user = await UserModel.findOne({ refreshToken }); + if (!user) { + return res.status(403).json( + { + message: "Invalid refresh token" + } + ); } - user.tokenVersion += 1; - await user.save(); - const newAccessToken = jwt.sign( - { username: user.username, id: user._id }, - process.env.ACCESS_TOKEN_SECERT, - { expiresIn: "45m" } - ); - res.header("Authorization", `Bearer ${newAccessToken}`); - res.status(200).json({ accessToken: newAccessToken }); - user.prevAccessToken.push(token); - await user.save(); + + jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, async (err, decoded) => { + if (err) return res.status(403).json( + { + message: "Invalid token" + } + ); + + const newAccessToken = generateAccessToken(user); + res.status(200).json({ accessToken: newAccessToken }); + }); } catch (error) { - console.log(error); - res.status(500).json({ error: "Internal server error" }); + console.error(error); + res.status(500).json( + { + message: "Internal server error" + } + ); } }; -const generateRefreshToken = (user) => { - return jwt.sign( - { username: user.username, id: user._id }, - process.env.REFRESH_TOKEN_SECERT - ); -}; module.exports = { registerUser, loginUser, refreshToken }; diff --git a/controllers/questionController.js b/controllers/questionController.js index f263bdd..1f3e522 100644 --- a/controllers/questionController.js +++ b/controllers/questionController.js @@ -5,15 +5,17 @@ const questionModel = require("../models/questionModel"); const questionFilePath = path.join(__dirname, "../questions.json"); -//getQuestions based on difficulyLevel const getQuestions = async (req, res) => { const { id } = req.params; const { difficultyLevel } = req.query; + try { - if (questionModel.length === 0) { - return res.status(200).json({ + if (!questionModel.length) { + return res.status(200).json( + { message: "No questions available.", - }); + } + ); } const existingUnansweredQuestion = await questionModel.findOne({ @@ -69,7 +71,6 @@ const getQuestions = async (req, res) => { } }; -//getAllQuestions based on users const getAllQuestions = async (req, res) => { try { const allQuestions = await questionModel.find({ @@ -80,7 +81,6 @@ const getAllQuestions = async (req, res) => { .status(404) .json({ message: "The user haven't started the game." }); } - // console.log(allQuestions); res.status(200).json(allQuestions); } catch (error) { console.error(error); @@ -88,7 +88,6 @@ const getAllQuestions = async (req, res) => { } }; -//getAllAnsweredQuestions based on users const getAllAnsweredQuestions = async (req, res) => { try { const allQuestions = await questionModel.find({ @@ -98,9 +97,12 @@ const getAllAnsweredQuestions = async (req, res) => { if (allQuestions.length === 0) { return res .status(404) - .json({ message: "The user haven't started the game." }); + .json( + { + message: "The user haven't started the game." + } + ); } - // console.log(allQuestions); res.status(200).json(allQuestions); } catch (error) { console.error(error); @@ -108,7 +110,6 @@ const getAllAnsweredQuestions = async (req, res) => { } }; -//postAnswer const postAnswerQuestion = async (req, res) => { try { const { id } = req.params; @@ -117,7 +118,11 @@ const postAnswerQuestion = async (req, res) => { const user = await userModel.findById(id); if (!user) { - return res.status(404).json({ message: "User not found." }); + return res.status(404).json( + { + message: "User not found." + } + ); } console.log("user", user); const postAnswers = await questionModel.findOne({ @@ -130,7 +135,11 @@ const postAnswerQuestion = async (req, res) => { if (typeof points !== "number") { return res .status(400) - .json({ message: "Invalid score. Score must be a number" }); + .json( + { + message: "Invalid score. Score must be a number" + } + ); } if (postAnswers) { const questions = JSON.parse(fs.readFileSync(questionFilePath, "utf8")); @@ -161,7 +170,11 @@ const postAnswerQuestion = async (req, res) => { updatedScore: updatedScore, }); } else { - return res.status(404).json({ message: "User not found." }); + return res.status(404).json( + { + message: "User not found." + } + ); } } else { await userModel.findByIdAndUpdate(id, { @@ -183,9 +196,11 @@ const postAnswerQuestion = async (req, res) => { } } console.log("postAnswers", postAnswers); - return res.status(404).json({ + return res.status(404).json( + { message: "Already answered the question", - }); + } + ); } catch (error) { console.error(error); res.status(500).json({ error: "Internal Server Error" }); @@ -223,7 +238,12 @@ const getAnsweringStatus = async (req, res) => { } } console.log(user); - return res.status(200).json({ canAnswer, message: "User can answer" }); + return res.status(200).json( + { + canAnswer, + message: "User can answer" + } + ); } catch (error) { console.error(error); res.status(500).json({ error: "Internal Server Error" }); diff --git a/controllers/userController.js b/controllers/userController.js index d16591f..41442b3 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,27 +1,22 @@ const UserModel = require("../models/userModel"); const bcrypt = require("bcrypt"); -const getAllUser = async (req, res) => { +const getAllUsers = async (req, res) => { try { - const page = parseInt(req.query.page) - 1 || 0; + const page = Math.max(parseInt(req.query.page) - 1, 0) || 0; const limit = parseInt(req.query.limit) || 10000000; const skip = page * limit; - let sort = req.query.sort || "score"; + const sortParam = req.query.sort ? req.query.sort.split(",") : ["score"]; + const sortBy = { [sortParam[0]]: sortParam[1] || "desc" }; - req.query.sort ? (sort = req.query.sort.split(",")) : (sort = [sort]); - let sortBy = {}; - if (sort[1]) { - sortBy[sort[0]] = sort[1]; - } else { - sortBy[sort[0]] = "desc"; - } const users = await UserModel.find({ isAdmin: false }) .select("username score updatedAnswerAt isBan") - .sort({ score: "desc", updatedAnswerAt: "asc" }) + .sort(sortBy) .skip(skip) .limit(limit) .exec(); + res.status(200).json(users); } catch (error) { console.error(error); @@ -29,105 +24,86 @@ const getAllUser = async (req, res) => { } }; -//update user score const updateScore = async (req, res) => { const { username, newscore } = req.body; + + if (typeof newscore !== "number") { + return res.status(400).json({ message: "Invalid score. Must be a number." }); + } + try { - if (typeof newscore !== "number") { - return res - .status(400) - .json({ message: "Invalid score. Score must be a number" }); - } - const user = await UserModel.findOne({ username: username }); + const user = await UserModel.findOneAndUpdate( + { username }, + { $set: { score: newscore } }, + { new: true } + ); + if (!user) { return res.status(404).json({ message: "User not found" }); } - await UserModel.updateOne( - { username: username }, - { $set: { score: newscore } } - ); + res.status(200).json({ message: "Score updated successfully" }); } catch (error) { + console.error(error); res.status(500).json({ error: "Internal Server Error" }); } }; -//update user password const updatePassword = async (req, res) => { const { username, newpassword } = req.body; + try { - const user = await UserModel.findOne({ username: username }); - if (!user) { - return res.status(404).json({ message: "User not found" }); - } - const salt = await bcrypt.genSalt(10); - const hashedPassword = await bcrypt.hash(newpassword, salt); - await UserModel.updateOne( - { username: username }, - { $set: { password: hashedPassword } } - ); - await user.save(); + const user = await UserModel.findOne({ username }); + if (!user) return res.status(404).json({ message: "User not found" }); + + const hashedPassword = await bcrypt.hash(newpassword, 10); + await UserModel.updateOne({ username }, { $set: { password: hashedPassword } }); + res.status(200).json({ message: "Password updated successfully" }); } catch (error) { - console.log(error); + console.error(error); res.status(500).json({ error: "Internal Server Error" }); } }; -//Update Ban status const isBanStatus = async (req, res) => { const { username, banstatus } = req.body; + + if (typeof banstatus !== "boolean") { + return res.status(400).json({ message: "Invalid input. Must be a boolean." }); + } + try { const user = await UserModel.findOne({ username }); + if (!user) return res.status(404).json({ message: "User not found" }); - if (!user) { - return res.status(404).json({ message: "User not found" }); - } - if (typeof banstatus !== "boolean") { - return res - .status(400) - .json({ message: "Invalid ban input. it must be a boolean" }); - } - - if (user.isBan && banstatus === true) { - const TimeOut = 15 * 60 * 1000; - + if (user.isBan && banstatus) { + const timeoutDuration = 15 * 60 * 1000; const timeElapsed = Date.now() - user.banTime; - - if (timeElapsed < TimeOut) { - const remainingTime = TimeOut - timeElapsed; - await UserModel.findByIdAndUpdate(req.params.id, { isBan: true }); + + if (timeElapsed < timeoutDuration) { return res.status(200).json({ - message: `User has banned already. Please wait for ${remainingTime} milliseconds.`, - remainingTime: remainingTime, + message: `User is already banned. Please wait ${timeoutDuration - timeElapsed} ms before unbanning.`, + remainingTime: timeoutDuration - timeElapsed, isBan: user.isBan, }); } } - if (banstatus === true) { - banTime = new Date(); + const updateFields = banstatus ? { isBan: true, banTime: Date.now() } : { isBan: false, banTime: null }; + await UserModel.updateOne({ username }, { $set: updateFields }); + + if (banstatus) { setTimeout(async () => { - await UserModel.updateOne({ username }, { isBan: false }); + await UserModel.updateOne({ username }, { $set: { isBan: false } }); }, 15 * 60 * 1000); - await UserModel.updateOne( - { username: username }, - { $set: { isBan: banstatus, banTime: banTime } } - ); - } else { - await UserModel.updateOne( - { username: username }, - { $set: { isBan: banstatus, banTime: null } } - ); } - res - .status(200) - .json({ user, message: `Ban status updated successfully ${banstatus}` }); + res.status(200).json({ message: `Ban status updated successfully to ${banstatus}` }); } catch (error) { - console.log(error); + console.error(error); res.status(500).json({ error: "Internal Server Error" }); } }; -module.exports = { getAllUser, updateScore, updatePassword, isBanStatus }; +module.exports = { getAllUsers, updateScore, updatePassword, isBanStatus }; diff --git a/index.js b/index.js index febc09e..cd4906d 100644 --- a/index.js +++ b/index.js @@ -20,6 +20,8 @@ app.use("/auth", AuthRoute); app.use("/users", userRoute); app.use("/questions", questionRoute); +app.get("") + app.listen(port, () => { console.log(`Server running on port ${port}`); }); From 420b7963d6bd65e49d50de201a8e5f7cb15cc3de Mon Sep 17 00:00:00 2001 From: ABHINAVGARG05 Date: Tue, 18 Feb 2025 09:05:19 +0530 Subject: [PATCH 2/2] fix --- controllers/questionController.js | 17 ++++++++++++----- routes/userRoute.js | 2 -- seeders/seedQuestions.js | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/controllers/questionController.js b/controllers/questionController.js index 1f3e522..9f31ce3 100644 --- a/controllers/questionController.js +++ b/controllers/questionController.js @@ -10,12 +10,19 @@ const getQuestions = async (req, res) => { const { difficultyLevel } = req.query; try { - if (!questionModel.length) { - return res.status(200).json( - { + + const isLastAnswered = await checkLastQuestionAnswered(id, difficultyLevel); + if (!isLastAnswered) { + return res.status(400).json({ + message: "Please answer the last question before getting a new one.", + }); + } + + const totalQuestions = await questionModel.countDocuments(); + if (totalQuestions === 0) { + return res.status(200).json({ message: "No questions available.", - } - ); + }); } const existingUnansweredQuestion = await questionModel.findOne({ diff --git a/routes/userRoute.js b/routes/userRoute.js index 1c0cb7b..9bd7c2e 100644 --- a/routes/userRoute.js +++ b/routes/userRoute.js @@ -1,6 +1,5 @@ const express = require("express"); const { - getAllUser, updateScore, updatePassword, isBanStatus, @@ -9,7 +8,6 @@ const isAdmin = require("../middleware/validateAdminHandler"); const router = express.Router(); -router.get("/allusers", getAllUser); router.put("/updatepassword", isAdmin, updatePassword); router.put("/updatescore", isAdmin, updateScore); router.put("/updateban", isAdmin, isBanStatus); diff --git a/seeders/seedQuestions.js b/seeders/seedQuestions.js index dfcab10..634f1bd 100644 --- a/seeders/seedQuestions.js +++ b/seeders/seedQuestions.js @@ -1,4 +1,6 @@ // seedQuestions.js +require("dotenv").config({ path: "../.env" }); +console.log(process.env.CONNECT_STRING) const mongoose = require("mongoose"); const fs = require("fs"); const path = require("path");