forked from CSI-KJSCE/appointment_to_examiner
Fixes for Admin Login, @somaiya.edu validation, and Password Visibility
This commit is contained in:
@@ -40,6 +40,9 @@ const CourseForm = () => {
|
|||||||
|
|
||||||
const [errors, setErrors] = useState({});
|
const [errors, setErrors] = useState({});
|
||||||
|
|
||||||
|
// State to check if the form is currently submitting
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchOptionsAndFaculties = async () => {
|
const fetchOptionsAndFaculties = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -86,7 +89,6 @@ const CourseForm = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleRemoveFaculty = (field, index) => {
|
const handleRemoveFaculty = (field, index) => {
|
||||||
setTempAssignments((prev) => {
|
setTempAssignments((prev) => {
|
||||||
const updatedAssignments = [...prev[field]];
|
const updatedAssignments = [...prev[field]];
|
||||||
@@ -139,6 +141,10 @@ const CourseForm = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const payload = Object.values(groupedTasks);
|
const payload = Object.values(groupedTasks);
|
||||||
|
|
||||||
|
// Start loading so user knows it is saving
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
await saveAppointment(payload);
|
await saveAppointment(payload);
|
||||||
// await updateCourseStatus(course?.courseId || id);
|
// await updateCourseStatus(course?.courseId || id);
|
||||||
|
|
||||||
@@ -152,6 +158,8 @@ const CourseForm = () => {
|
|||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to save appointment:", error);
|
console.error("Failed to save appointment:", error);
|
||||||
|
// If error comes, stop the loading
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -343,8 +351,10 @@ const CourseForm = () => {
|
|||||||
type="submit"
|
type="submit"
|
||||||
className="courseFormButton"
|
className="courseFormButton"
|
||||||
style={{ gridColumn: "1 / -1" }}
|
style={{ gridColumn: "1 / -1" }}
|
||||||
|
disabled={loading} // Disable button when loading
|
||||||
>
|
>
|
||||||
Submit
|
{/* Change text based on loading state */}
|
||||||
|
{loading ? "Saving..." : "Submit"}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Container, Col, Row } from "react-bootstrap";
|
import { Container, Col, Row } from "react-bootstrap";
|
||||||
import { FcGoogle } from "react-icons/fc";
|
import { FcGoogle } from "react-icons/fc";
|
||||||
|
import { FaEye, FaEyeSlash } from "react-icons/fa";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import md5 from "md5";
|
import md5 from "md5";
|
||||||
|
|
||||||
@@ -39,18 +40,26 @@ function AuthPage() {
|
|||||||
|
|
||||||
async function handleSubmit(event) {
|
async function handleSubmit(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
// check if username is there
|
||||||
if (!formData.username.trim() && signin) {
|
if (!formData.username.trim() && signin) {
|
||||||
notifyError("Username cannot be empty");
|
notifyError("Username cannot be empty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check email format
|
||||||
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||||
if (!emailRegex.test(formData.email)) {
|
if (!emailRegex.test(formData.email)) {
|
||||||
notifyError("Enter a valid email address");
|
notifyError("Enter a valid email address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check password length
|
// restrict to somaiya emails
|
||||||
|
if (formData.email.endsWith("@somaiya.edu") === false) {
|
||||||
|
notifyError("Only @somaiya.edu emails are allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// password validation
|
||||||
if (formData.password.length < 8) {
|
if (formData.password.length < 8) {
|
||||||
notifyError("Password must be at least 8 characters long");
|
notifyError("Password must be at least 8 characters long");
|
||||||
return;
|
return;
|
||||||
@@ -164,12 +173,17 @@ function TogglerContainer(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SignUpForm(props) {
|
function SignUpForm(props) {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form>
|
<form onSubmit={props.handleSubmit}>
|
||||||
<h1>Create Account</h1>
|
<h1>Create Account</h1>
|
||||||
<div className="Googlediv">
|
<div className="Googlediv">
|
||||||
<button className="GoogleBtn" onClick={props.handleGoogleLogin}>
|
<button
|
||||||
|
type="button"
|
||||||
|
className="GoogleBtn"
|
||||||
|
onClick={props.handleGoogleLogin}
|
||||||
|
>
|
||||||
<FcGoogle className="icon" /> Sign up with Google
|
<FcGoogle className="icon" /> Sign up with Google
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,27 +204,48 @@ function SignUpForm(props) {
|
|||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<div style={{ position: "relative", width: "100%" }}>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type={showPassword ? "text" : "password"}
|
||||||
name="password"
|
name="password"
|
||||||
value={props.formData.password}
|
value={props.formData.password}
|
||||||
onChange={props.handleInputChange}
|
onChange={props.handleInputChange}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
required
|
required
|
||||||
|
style={{ paddingRight: "40px" }}
|
||||||
/>
|
/>
|
||||||
<button onClick={props.handleSubmit}>Sign Up</button>
|
<span
|
||||||
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
right: "10px",
|
||||||
|
top: "50%",
|
||||||
|
transform: "translateY(-50%)",
|
||||||
|
cursor: "pointer",
|
||||||
|
color: "#666",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showPassword ? <FaEyeSlash /> : <FaEye />}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Sign Up</button>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SignInForm(props) {
|
function SignInForm(props) {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form>
|
<form onSubmit={props.handleSubmit}>
|
||||||
<h1>Sign In</h1>
|
<h1>Sign In</h1>
|
||||||
<div>
|
<div>
|
||||||
<button className="GoogleBtn" onClick={props.handleGoogleLogin}>
|
<button
|
||||||
|
type="button"
|
||||||
|
className="GoogleBtn"
|
||||||
|
onClick={props.handleGoogleLogin}
|
||||||
|
>
|
||||||
<FcGoogle className="icon" /> Sign in with Google
|
<FcGoogle className="icon" /> Sign in with Google
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -223,16 +258,32 @@ function SignInForm(props) {
|
|||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<div style={{ position: "relative", width: "100%" }}>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type={showPassword ? "text" : "password"}
|
||||||
name="password"
|
name="password"
|
||||||
value={props.formData.password}
|
value={props.formData.password}
|
||||||
onChange={props.handleInputChange}
|
onChange={props.handleInputChange}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
required
|
required
|
||||||
|
style={{ paddingRight: "40px" }}
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
right: "10px",
|
||||||
|
top: "50%",
|
||||||
|
transform: "translateY(-50%)",
|
||||||
|
cursor: "pointer",
|
||||||
|
color: "#666",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showPassword ? <FaEyeSlash /> : <FaEye />}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<a href="/ForgetPw">Forget Your Password?</a>
|
<a href="/ForgetPw">Forget Your Password?</a>
|
||||||
<button onClick={props.handleSubmit}>Sign In</button>
|
<button type="submit">Sign In</button>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
BIN
client/src/assets/Somaiya.jpg
Normal file
BIN
client/src/assets/Somaiya.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 317 KiB |
@@ -13,6 +13,14 @@ passport.use(
|
|||||||
},
|
},
|
||||||
async (accessToken, refreshToken, profile, done) => {
|
async (accessToken, refreshToken, profile, done) => {
|
||||||
try {
|
try {
|
||||||
|
// Security: Check if the email is from Somaiya
|
||||||
|
// We only want somaiya students/faculty to access this
|
||||||
|
if (profile.emails[0].value.endsWith("@somaiya.edu") === false) {
|
||||||
|
return done(null, false, {
|
||||||
|
message: "Only @somaiya.edu emails are allowed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Check if a user with the same email already exists
|
// Check if a user with the same email already exists
|
||||||
let user = await User.findOne({ email: profile.emails[0].value });
|
let user = await User.findOne({ email: profile.emails[0].value });
|
||||||
|
|
||||||
|
|||||||
25
server/middleware/verifyAdmin.js
Normal file
25
server/middleware/verifyAdmin.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
|
const verifyAdmin = (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const token = req.cookies.token; // Ensure you are using cookies for auth
|
||||||
|
if (!token) {
|
||||||
|
return res
|
||||||
|
.status(401)
|
||||||
|
.json({ message: "Access denied. No token provided." });
|
||||||
|
}
|
||||||
|
|
||||||
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||||
|
// Check if user is admin based on the 'isAdmin' boolean in the token
|
||||||
|
if (!decoded.isAdmin) {
|
||||||
|
return res.status(403).json({ message: "Access denied. Admins only." });
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user = decoded; // Attach user data to the request
|
||||||
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
res.status(401).json({ message: "Invalid or expired token" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = verifyAdmin;
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.0",
|
||||||
"googleapis": "^134.0.0",
|
"googleapis": "^134.0.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.3",
|
||||||
"mongodb": "^6.15.0",
|
"mongodb": "^6.15.0",
|
||||||
"mongoose": "^8.9.5",
|
"mongoose": "^8.9.5",
|
||||||
"mongoose-findorcreate": "^4.0.0",
|
"mongoose-findorcreate": "^4.0.0",
|
||||||
@@ -42,6 +42,8 @@
|
|||||||
"uuid": "^11.0.3"
|
"uuid": "^11.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^3.1.0"
|
"jest": "^30.2.0",
|
||||||
|
"nodemon": "^3.1.0",
|
||||||
|
"supertest": "^7.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const Course = require("../models/Course");
|
const Course = require("../models/Course");
|
||||||
const verifyAdmin = require("../../client/src/components/verifyAdmin");
|
const verifyAdmin = require("../middleware/verifyAdmin");
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -21,7 +21,6 @@ router.get("/", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Get course by ID
|
// Get course by ID
|
||||||
router.get("/:id", async (req, res) => {
|
router.get("/:id", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@@ -91,7 +90,9 @@ router.put("/:courseId", verifyAdmin, async (req, res) => {
|
|||||||
//delete
|
//delete
|
||||||
router.delete("/:courseId", verifyAdmin, async (req, res) => {
|
router.delete("/:courseId", verifyAdmin, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const deletedCourse = await Course.findOneAndDelete({ courseId: req.params.courseId });
|
const deletedCourse = await Course.findOneAndDelete({
|
||||||
|
courseId: req.params.courseId,
|
||||||
|
});
|
||||||
if (!deletedCourse) {
|
if (!deletedCourse) {
|
||||||
return res.status(404).json({ error: "Course not found" });
|
return res.status(404).json({ error: "Course not found" });
|
||||||
}
|
}
|
||||||
@@ -105,7 +106,8 @@ router.delete("/:courseId", verifyAdmin, async (req, res) => {
|
|||||||
// add a new course
|
// add a new course
|
||||||
router.post("/", verifyAdmin, async (req, res) => {
|
router.post("/", verifyAdmin, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { courseId, name, department, program, scheme, semester, status } = req.body;
|
const { courseId, name, department, program, scheme, semester, status } =
|
||||||
|
req.body;
|
||||||
|
|
||||||
// Check if a course with the same courseId already exists
|
// Check if a course with the same courseId already exists
|
||||||
const existingCourse = await Course.findOne({ courseId });
|
const existingCourse = await Course.findOne({ courseId });
|
||||||
@@ -120,17 +122,17 @@ router.post("/", verifyAdmin, async (req, res) => {
|
|||||||
program,
|
program,
|
||||||
scheme,
|
scheme,
|
||||||
semester,
|
semester,
|
||||||
status
|
status,
|
||||||
});
|
});
|
||||||
|
|
||||||
await newCourse.save();
|
await newCourse.save();
|
||||||
res.status(201).json({ message: "Course added successfully", course: newCourse });
|
res
|
||||||
|
.status(201)
|
||||||
|
.json({ message: "Course added successfully", course: newCourse });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error adding course:", error);
|
console.error("Error adding course:", error);
|
||||||
res.status(500).json({ error: "Failed to add course" });
|
res.status(500).json({ error: "Failed to add course" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
112
server/server.js
112
server/server.js
@@ -22,20 +22,32 @@ const Course = require("./models/Course");
|
|||||||
const User = require("./models/User");
|
const User = require("./models/User");
|
||||||
|
|
||||||
// MongoDB Connection
|
// MongoDB Connection
|
||||||
mongoose
|
// MongoDB Connection
|
||||||
.connect(process.env.mongoURI, { useNewUrlParser: true, useUnifiedTopology: true })
|
const connectDB = async () => {
|
||||||
.then(() => console.log("MongoDB connected"))
|
try {
|
||||||
.catch((err) => {
|
await mongoose.connect(process.env.mongoURI, {
|
||||||
console.error("MongoDB connection error:", err);
|
useNewUrlParser: true,
|
||||||
process.exit(1); // Exit the app if the database connection fails
|
useUnifiedTopology: true,
|
||||||
});
|
});
|
||||||
|
console.log("MongoDB connected");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("MongoDB connection failed:", err.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
connectDB();
|
||||||
|
|
||||||
// Initialize App
|
// Initialize App
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = 8080;
|
const PORT = 8080;
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use(cors({ origin: process.env.CORS_ORIGIN || "http://localhost:3000", credentials: true }));
|
app.use(
|
||||||
|
cors({
|
||||||
|
origin: process.env.CORS_ORIGIN || "http://localhost:3000",
|
||||||
|
credentials: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
app.use(cookieparser());
|
app.use(cookieparser());
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
@@ -74,9 +86,19 @@ app.get(
|
|||||||
"/auth/google/callback",
|
"/auth/google/callback",
|
||||||
passport.authenticate("google", { failureRedirect: "/" }),
|
passport.authenticate("google", { failureRedirect: "/" }),
|
||||||
(req, res) => {
|
(req, res) => {
|
||||||
const token = jwt.sign({ userId: req.user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
const token = jwt.sign(
|
||||||
|
{ userId: req.user._id, isAdmin: req.user.isAdmin },
|
||||||
|
process.env.JWT_SECRET,
|
||||||
|
{
|
||||||
|
expiresIn: "1h",
|
||||||
|
}
|
||||||
|
);
|
||||||
// Set token as a cookie or send it in the response
|
// Set token as a cookie or send it in the response
|
||||||
res.cookie("token", token, { httpOnly: true, secure: false, maxAge: 3600000 });
|
res.cookie("token", token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: false,
|
||||||
|
maxAge: 3600000,
|
||||||
|
});
|
||||||
res.redirect("http://localhost:3000/Welcome"); // Redirect to a frontend route after successful login
|
res.redirect("http://localhost:3000/Welcome"); // Redirect to a frontend route after successful login
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -85,6 +107,14 @@ app.get(
|
|||||||
app.post("/api/register", async (req, res) => {
|
app.post("/api/register", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { username, email, password } = req.body;
|
const { username, email, password } = req.body;
|
||||||
|
|
||||||
|
// Validation: Only allow somaiya emails
|
||||||
|
if (email.endsWith("@somaiya.edu") === false) {
|
||||||
|
return res
|
||||||
|
.status(400)
|
||||||
|
.json({ message: "Only @somaiya.edu emails are allowed" });
|
||||||
|
}
|
||||||
|
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
let user = await User.findOne({ email });
|
let user = await User.findOne({ email });
|
||||||
|
|
||||||
@@ -104,11 +134,21 @@ app.post("/api/register", async (req, res) => {
|
|||||||
await user.save();
|
await user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a JWT token using the user's ID
|
// adding isAdmin to token so we know if user is admin
|
||||||
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
const token = jwt.sign(
|
||||||
|
{ userId: user._id, isAdmin: user.isAdmin },
|
||||||
|
process.env.JWT_SECRET,
|
||||||
|
{
|
||||||
|
expiresIn: "1h",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Set the token as a cookie
|
// Set the token as a cookie
|
||||||
res.cookie("token", token, { httpOnly: true, secure: false, maxAge: 3600000 }); // 1 hour expiry
|
res.cookie("token", token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: false,
|
||||||
|
maxAge: 3600000,
|
||||||
|
}); // 1 hour expiry
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
message: "Registered and logged in successfully",
|
message: "Registered and logged in successfully",
|
||||||
@@ -133,10 +173,20 @@ app.post("/api/login", (req, res, next) => {
|
|||||||
return res.status(500).json({ message: "Internal server error" });
|
return res.status(500).json({ message: "Internal server error" });
|
||||||
}
|
}
|
||||||
// Generate a JWT token using the user's ID
|
// Generate a JWT token using the user's ID
|
||||||
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
const token = jwt.sign(
|
||||||
|
{ userId: user._id, isAdmin: user.isAdmin },
|
||||||
|
process.env.JWT_SECRET,
|
||||||
|
{
|
||||||
|
expiresIn: "1h",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Set the token as a cookie
|
// Set the token as a cookie
|
||||||
res.cookie("token", token, { httpOnly: true, secure: false, maxAge: 3600000 }); // 1 hour expiry
|
res.cookie("token", token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: false,
|
||||||
|
maxAge: 3600000,
|
||||||
|
}); // 1 hour expiry
|
||||||
return res.status(200).json({ message: "Login successful", user });
|
return res.status(200).json({ message: "Login successful", user });
|
||||||
});
|
});
|
||||||
})(req, res, next);
|
})(req, res, next);
|
||||||
@@ -158,7 +208,9 @@ app.get("/auth/logout", function (req, res) {
|
|||||||
console.error("Error destroying session:", err);
|
console.error("Error destroying session:", err);
|
||||||
return res.status(500).json({ message: "Error logging out" });
|
return res.status(500).json({ message: "Error logging out" });
|
||||||
}
|
}
|
||||||
res.status(200).json({ message: "Logout successful, session destroyed" });
|
res
|
||||||
|
.status(200)
|
||||||
|
.json({ message: "Logout successful, session destroyed" });
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// If no session, simply respond with success
|
// If no session, simply respond with success
|
||||||
@@ -175,12 +227,18 @@ app.post("/api/refresh", (req, res) => {
|
|||||||
const refreshToken = req.cookies.token;
|
const refreshToken = req.cookies.token;
|
||||||
|
|
||||||
if (!refreshToken) {
|
if (!refreshToken) {
|
||||||
return res.status(401).json({ message: "No refresh token, authorization denied" });
|
return res
|
||||||
|
.status(401)
|
||||||
|
.json({ message: "No refresh token, authorization denied" });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET);
|
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET);
|
||||||
const newToken = jwt.sign({ userId: decoded.userId }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
const newToken = jwt.sign(
|
||||||
|
{ userId: decoded.userId, isAdmin: decoded.isAdmin },
|
||||||
|
process.env.JWT_SECRET,
|
||||||
|
{ expiresIn: "1h" }
|
||||||
|
);
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.cookie("token", newToken, { httpOnly: true, maxAge: 3600000 }) // Set new access token
|
.cookie("token", newToken, { httpOnly: true, maxAge: 3600000 }) // Set new access token
|
||||||
@@ -196,7 +254,6 @@ app.get("/api/auth-check", (req, res) => {
|
|||||||
const token = req.cookies.token; // Retrieve the httpOnly cookie
|
const token = req.cookies.token; // Retrieve the httpOnly cookie
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
console.log("Tehehe");
|
|
||||||
return res.status(401).json({ message: "Unauthorized" });
|
return res.status(401).json({ message: "Unauthorized" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +268,8 @@ app.get("/api/auth-check", (req, res) => {
|
|||||||
app.get("/api/me", async (req, res) => {
|
app.get("/api/me", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const token = req.cookies.token; // ✅ Get token from request cookies
|
const token = req.cookies.token; // ✅ Get token from request cookies
|
||||||
if (!token) return res.status(401).json({ message: "Unauthorized - No Token" });
|
if (!token)
|
||||||
|
return res.status(401).json({ message: "Unauthorized - No Token" });
|
||||||
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET); // ✅ Verify token
|
const decoded = jwt.verify(token, process.env.JWT_SECRET); // ✅ Verify token
|
||||||
|
|
||||||
@@ -223,16 +281,14 @@ app.get("/api/me", async (req, res) => {
|
|||||||
userId: user._id,
|
userId: user._id,
|
||||||
isAdmin: user.isAdmin, // ✅ Return actual `isAdmin` value
|
isAdmin: user.isAdmin, // ✅ Return actual `isAdmin` value
|
||||||
exp: decoded.exp,
|
exp: decoded.exp,
|
||||||
iat: decoded.iat
|
iat: decoded.iat,
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("JWT Verification Error:", error.message);
|
console.error("JWT Verification Error:", error.message);
|
||||||
res.status(401).json({ message: "Invalid token" });
|
res.status(401).json({ message: "Invalid token" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// User Profile Route
|
// User Profile Route
|
||||||
app.get("/api/user/profile", async (req, res) => {
|
app.get("/api/user/profile", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@@ -251,9 +307,6 @@ app.patch("/api/courses/:courseId", async (req, res) => {
|
|||||||
const { courseId } = req.params;
|
const { courseId } = req.params;
|
||||||
const { status } = req.body;
|
const { status } = req.body;
|
||||||
|
|
||||||
console.log("Request params:", req.params);
|
|
||||||
console.log("Request body:", req.body);
|
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
console.error("Status is missing in the request body.");
|
console.error("Status is missing in the request body.");
|
||||||
return res.status(400).json({ message: "Status is required" });
|
return res.status(400).json({ message: "Status is required" });
|
||||||
@@ -287,10 +340,17 @@ app.get("*", (req, res) =>
|
|||||||
// Error Handling Middleware
|
// Error Handling Middleware
|
||||||
app.use((err, req, res, next) => {
|
app.use((err, req, res, next) => {
|
||||||
console.error("Error:", err.stack);
|
console.error("Error:", err.stack);
|
||||||
res.status(err.status || 500).json({ error: err.message || "Internal Server Error" });
|
res
|
||||||
|
.status(err.status || 500)
|
||||||
|
.json({ error: err.message || "Internal Server Error" });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start Server
|
// Start Server
|
||||||
|
// Start Server
|
||||||
|
if (require.main === module) {
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`Server is running at http://localhost:8080`);
|
console.log(`Server is running at http://localhost:8080`);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = app;
|
||||||
|
|||||||
Reference in New Issue
Block a user