Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
MONGODB_URI=mongodb://localhost:27017/classsync
PORT=3000

JWT_SECRET="yoursecret"
GROQ_API_KEY=""

GOOGLE_MAILID=
GOOGLE_APP_PASSWORD=

CORS_ORIGIN=http://localhost:5173
28 changes: 24 additions & 4 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
"type": "commonjs",
"dependencies": {
"bcrypt": "^6.0.0",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.15.1",
"node-cron": "^4.1.1",
"nodemailer": "^7.0.3",
"nodemailer": "^7.0.6",
"openai": "^5.8.2"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions backend/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ require('dotenv').config();
const express = require('express');
const cors = require('cors');
const connectDB = require('./config/db');
const cookieParser = require('cookie-parser');

const app = express();
connectDB();
Expand All @@ -16,6 +17,7 @@ const corsOptions = {

app.use(cors(corsOptions));
app.use(express.json());
app.use(cookieParser());

const chatbotRoutes = require('./routes/chatbotRoutes');
app.use('/api/chatbot', chatbotRoutes);
Expand Down
150 changes: 136 additions & 14 deletions backend/src/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
const User = require('../models/User');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require("../models/User");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const nodemailer = require("nodemailer");

const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.GOOGLE_MAILID,
pass: process.env.GOOGLE_APP_PASSWORD,
},
});

// Register new user
exports.register = async (req, res) => {
try {
const { name, email, password, role, schoolId } = req.body;

if (!schoolId) {
return res.status(400).json({ message: 'schoolId is required' });
return res.status(400).json({ message: "schoolId is required" });
}

// Check if user exists
let user = await User.findOne({ email });
if (user) return res.status(400).json({ message: 'User already exists' });
if (user) return res.status(400).json({ message: "User already exists" });

// Hash password
const salt = await bcrypt.genSalt(10);
Expand All @@ -30,13 +39,20 @@ exports.register = async (req, res) => {
await user.save();

// Create JWT token
const payload = { userId: user._id, role: user.role, email: user.email, name: user.name };
const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1d' });
const payload = {
userId: user._id,
role: user.role,
email: user.email,
name: user.name,
};
const token = jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: "1d",
});

res.status(201).json({ token });
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
res.status(500).send("Server error");
}
};

Expand All @@ -47,28 +63,134 @@ exports.login = async (req, res) => {

// Find user
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ message: 'Invalid credentials' });
if (!user) return res.status(400).json({ message: "Invalid credentials" });

// Check password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ message: 'Invalid credentials' });
if (!isMatch)
return res.status(400).json({ message: "Invalid credentials" });

// Create JWT token
const payload = { userId: user._id, role: user.role, email: user.email, name: user.name };
const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1d' });
const payload = {
userId: user._id,
role: user.role,
email: user.email,
name: user.name,
};
const token = jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: "1d",
});

res.json({ token });
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
res.status(500).send("Server error");
}
};

exports.sendotp = async (req, res) => {
try {
console.log("triggered");
const { email } = req.body;
const user = await User.findOne({ email });

if (!user) return res.status(400).json({ message: "No such user found." });

const otp = Math.floor(100000 + Math.random() * 900000);

const mailOptions = {
from: process.env.GOOGLE_MAILID,
to: email,
subject: "OTP for password change request",
html: `<p>Dear User,</p>
<p>Your OTP for the password change request is <strong style="color:#4f46e5;">${otp}</strong>.</p>
<p>Please do not share this OTP with anyone to keep your account secure.</p>
<p>Thank you,<br />The Support Team,ClassSync</p>`,
};

const otpToken = jwt.sign({ otp, email }, process.env.JWT_SECRET, {
expiresIn: "5m",
});

res.cookie('otpToken',otpToken,{
httpOnly: true,
maxAge: 5 * 60 * 1000
});

await transporter.sendMail(mailOptions);
console.log("sent");
return res.status(200).json({message:'Otp sent'});
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
};

exports.verifyotp = async (req, res) => {
try {
const { otp } = req.body;
const otpToken = req.cookies.otpToken;
console.log("otpToken:", otpToken);
console.log("here");
const decoded = jwt.verify(otpToken, process.env.JWT_SECRET);
console.log("after");
if (otp == decoded.otp) {
return res.status(200).json({ message: "OTP verified successfully" });
} else {
return res.status(400).json({ message: "Wrong Otp" });
}
} catch (error) {
if (error.name === "TokenExpiredError") {
return res
.status(400)
.json({ message: "OTP expired. Please request a new one." });
}
console.error("yahai pe");
res.status(500).send("Server error");
}
};

exports.updatepassword = async (req,res) => {
try {
const {email, password, confirmPassword} = req.body;

let user = await User.findOne({ email });
if (!user) return res.status(400).json({ message: "User does not exists" });

if(password!=confirmPassword)
return res.status(400).json({message:'Passwords do not match.'});

const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);

user.password=hashedPassword;
await user.save();

const mailOptions = {
from: process.env.GOOGLE_MAILID,
to: email,
subject: "OTP for password change request",
html: `<p>Dear User,</p>
<p>Your password has been <strong>successfully updated.</strong>.</p>
<p>Please contact if you face any login issues.</p>
<p>Thank you,<br />The Support Team,ClassSync</p>`,
};

await transporter.sendMail(mailOptions);
res.clearCookie('otptoken');

return res.status(200).json({message:'Password updated successfully.'});
} catch (error) {
console.error(error.message);
res.status(500).send("Server Error");
}
}

//This code defines the authentication controller for user registration and login in an Express application.
// It includes functions to register a new user and log in an existing user, handling password hashing and JWT token generation.
// The `register` function checks if a user already exists, hashes the password, creates a new user, and returns a JWT token.
// The `login` function verifies the user's credentials, checks the password, and returns a JWT token if successful.
// The controller uses Mongoose for database operations, bcrypt for password hashing, and jsonwebtoken for token generation.
// The `register` function handles user registration, including password hashing and JWT token creation.
// The `login` function handles user login, verifying credentials and generating a JWT token.
// The controller responds with appropriate status codes and messages for success and error cases.
// The controller responds with appropriate status codes and messages for success and error cases.
6 changes: 5 additions & 1 deletion backend/src/routes/authRoutes.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
const express = require('express');
const router = express.Router();
const { register, login } = require('../controllers/authController');
const { register, login, sendotp, verifyotp, updatepassword } = require('../controllers/authController');

router.post('/register', register);
router.post('/login', login);

router.post('/sendotp',sendotp);
router.post('/verifyotp',verifyotp);
router.put('/updatepassword',updatepassword);

module.exports = router;
// This code defines the authentication routes for user registration and login.
// It imports the necessary modules, sets up the routes, and exports the router for use in the main application file.
Expand Down
1 change: 1 addition & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_API_URL=http://localhost:3000
8 changes: 4 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@
"globals": "^16.0.0",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.1",
"vite": "^6.3.5"
"vite": "^6.3.6"
}
}
Loading