271 lines
8.6 KiB
JavaScript
271 lines
8.6 KiB
JavaScript
const express = require("express");
|
|
const mongoose = require("mongoose");
|
|
const cors = require("cors");
|
|
const session = require("express-session");
|
|
const passport = require("passport");
|
|
const bodyParser = require("body-parser");
|
|
const path = require("path");
|
|
const bcrypt = require("bcryptjs");
|
|
const jwt = require("jsonwebtoken");
|
|
const cookieparser = require("cookie-parser");
|
|
require("dotenv").config();
|
|
|
|
// Import Routes
|
|
const authRoutes = require("./routes/authRoutes");
|
|
const courseRoutes = require("./routes/courseRoutes");
|
|
const facultyRoutes = require("./routes/facultyRoutes");
|
|
const appointmentRoutes = require("./routes/appointmentRoutes");
|
|
const optionsRoutes = require("./routes/optionsRoutes");
|
|
const consolidatedRoutes = require("./routes/consolidatedRoutes");
|
|
const emailRoutes = require("./routes/emailRoutes");
|
|
const Course = require("./models/Course");
|
|
|
|
// MongoDB Connection
|
|
mongoose
|
|
.connect(process.env.mongoURI, { useNewUrlParser: true, useUnifiedTopology: true })
|
|
.then(() => console.log("MongoDB connected"))
|
|
.catch((err) => {
|
|
console.error("MongoDB connection error:", err);
|
|
process.exit(1); // Exit the app if the database connection fails
|
|
});
|
|
|
|
// Initialize App
|
|
const app = express();
|
|
const PORT = 8080;
|
|
|
|
// Middleware
|
|
app.use(cors({ origin: "http://localhost:3000", credentials: true }));
|
|
app.use(cookieparser());
|
|
app.use(express.json());
|
|
app.use(bodyParser.urlencoded({ extended: true }));
|
|
app.use(
|
|
session({
|
|
secret: "secret", // This can be replaced with another secret from .env if required
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
})
|
|
);
|
|
app.use(passport.initialize());
|
|
app.use(passport.session());
|
|
|
|
app.use("/api/table", consolidatedRoutes);
|
|
|
|
// Passport Config
|
|
require("./config/passport");
|
|
|
|
// Routes
|
|
app.use("/password", authRoutes);
|
|
|
|
app.use("/api/courses", courseRoutes);
|
|
app.use("/api/faculty", facultyRoutes);
|
|
app.use("/api/appointments", appointmentRoutes);
|
|
app.use("/api/options", optionsRoutes);
|
|
app.use("/api/data", consolidatedRoutes);
|
|
app.use("/api/send-email", emailRoutes);
|
|
|
|
// Google OAuth Routes
|
|
app.get(
|
|
"/auth/google",
|
|
passport.authenticate("google", { scope: ["profile", "email"] })
|
|
);
|
|
|
|
app.get(
|
|
"/auth/google/callback",
|
|
passport.authenticate("google", { failureRedirect: "/" }),
|
|
(req, res) => {
|
|
const token = jwt.sign({ userId: req.user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
|
// Set token as a cookie or send it in the response
|
|
res.cookie("token", token, { httpOnly: true, secure: false, maxAge: 3600000 });
|
|
res.redirect("http://localhost:3000/Welcome"); // Redirect to a frontend route after successful login
|
|
}
|
|
);
|
|
|
|
// Local authentication routes (register and login)
|
|
app.post("/api/register", async (req, res) => {
|
|
try {
|
|
const { username, email, password } = req.body;
|
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
let user = await User.findOne({ email });
|
|
|
|
if (user) {
|
|
if (user.googleId && user.password) {
|
|
return res.status(400).json({ message: "User already exists" });
|
|
}
|
|
if (!user.googleId && user.password) {
|
|
return res.status(400).json({ message: "User already exists" });
|
|
}
|
|
if (user.googleId && !user.password) {
|
|
user.password = hashedPassword;
|
|
await user.save();
|
|
}
|
|
} else {
|
|
user = new User({ username, email, password: hashedPassword });
|
|
await user.save();
|
|
}
|
|
|
|
// Generate a JWT token using the user's ID
|
|
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
|
|
|
// Set the token as a cookie
|
|
res.cookie("token", token, { httpOnly: true, secure: false, maxAge: 3600000 }); // 1 hour expiry
|
|
|
|
return res.status(200).json({
|
|
message: "Registered and logged in successfully",
|
|
user,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error registering user:", error);
|
|
res.status(400).send("Registration failed");
|
|
}
|
|
});
|
|
|
|
app.post("/api/login", (req, res, next) => {
|
|
passport.authenticate("local", (err, user, info) => {
|
|
if (err) {
|
|
return res.status(500).json({ message: "Internal server error" });
|
|
}
|
|
if (!user) {
|
|
return res.status(401).json({ message: "Incorrect email or password" });
|
|
}
|
|
req.logIn(user, (err) => {
|
|
if (err) {
|
|
return res.status(500).json({ message: "Internal server error" });
|
|
}
|
|
// Generate a JWT token using the user's ID
|
|
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
|
|
|
// Set the token as a cookie
|
|
res.cookie("token", token, { httpOnly: true, secure: false, maxAge: 3600000 }); // 1 hour expiry
|
|
return res.status(200).json({ message: "Login successful", user });
|
|
});
|
|
})(req, res, next);
|
|
});
|
|
|
|
app.get("/auth/logout", function (req, res) {
|
|
try {
|
|
// Clear the token cookie
|
|
res.clearCookie("token", {
|
|
httpOnly: true, // Ensure it matches the cookie options you set earlier
|
|
secure: false, // Match the "secure" option from cookie settings
|
|
sameSite: "lax", // Ensure this matches the original cookie configuration
|
|
});
|
|
|
|
// Destroy the session if used (optional, if sessions are implemented)
|
|
if (req.session) {
|
|
req.session.destroy((err) => {
|
|
if (err) {
|
|
console.error("Error destroying session:", err);
|
|
return res.status(500).json({ message: "Error logging out" });
|
|
}
|
|
res.status(200).json({ message: "Logout successful, session destroyed" });
|
|
});
|
|
} else {
|
|
// If no session, simply respond with success
|
|
res.status(200).json({ message: "Logout successful, cookie cleared" });
|
|
}
|
|
} catch (err) {
|
|
console.error("Error logging out:", err);
|
|
res.status(500).json({ message: "Error logging out" });
|
|
}
|
|
});
|
|
|
|
// Refresh Token Endpoint
|
|
app.post("/api/refresh", (req, res) => {
|
|
const refreshToken = req.cookies.token;
|
|
|
|
if (!refreshToken) {
|
|
return res.status(401).json({ message: "No refresh token, authorization denied" });
|
|
}
|
|
|
|
try {
|
|
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET);
|
|
const newToken = jwt.sign({ userId: decoded.userId }, process.env.JWT_SECRET, { expiresIn: "1h" });
|
|
|
|
return res
|
|
.cookie("token", newToken, { httpOnly: true, maxAge: 3600000 }) // Set new access token
|
|
.status(200)
|
|
.json({ message: "Token refreshed" });
|
|
} catch (err) {
|
|
console.error("Error refreshing token:", err);
|
|
res.status(401).json({ message: "Invalid or expired refresh token" });
|
|
}
|
|
});
|
|
|
|
app.get("/api/auth-check", (req, res) => {
|
|
const token = req.cookies.token; // Retrieve the httpOnly cookie
|
|
|
|
if (!token) {
|
|
return res.status(401).json({ message: "Unauthorized" });
|
|
}
|
|
|
|
try {
|
|
jwt.verify(token, process.env.JWT_SECRET); // Verify the token
|
|
res.status(200).json({ authenticated: true }); // Valid token
|
|
} catch (err) {
|
|
res.status(401).json({ message: "Unauthorized" }); // Invalid token
|
|
}
|
|
});
|
|
|
|
|
|
// User Profile Route
|
|
app.get("/api/user/profile", async (req, res) => {
|
|
try {
|
|
if (req.user) {
|
|
return res.json({ user: req.user });
|
|
} else {
|
|
return res.status(401).json({ error: "Unauthorized" });
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching user data:", error);
|
|
res.status(500).json({ message: "Internal server error" });
|
|
}
|
|
});
|
|
|
|
app.patch("/api/courses/:courseId", async (req, res) => {
|
|
const { courseId } = req.params;
|
|
const { status } = req.body;
|
|
|
|
console.log("Request params:", req.params);
|
|
console.log("Request body:", req.body);
|
|
|
|
if (!status) {
|
|
console.error("Status is missing in the request body.");
|
|
return res.status(400).json({ message: "Status is required" });
|
|
}
|
|
|
|
try {
|
|
const updatedCourse = await Course.findOneAndUpdate(
|
|
{ courseId: courseId }, // Use courseId field for finding the course
|
|
{ status }, // Update the status field
|
|
{ new: true } // Return the updated document
|
|
);
|
|
|
|
if (!updatedCourse) {
|
|
console.error("Course not found:", courseId);
|
|
return res.status(404).json({ message: "Course not found" });
|
|
}
|
|
|
|
res.json(updatedCourse);
|
|
} catch (error) {
|
|
console.error("Error updating course status:", error.message);
|
|
res.status(500).json({ message: "Internal server error" });
|
|
}
|
|
});
|
|
|
|
// Serve React Build Files
|
|
app.use(express.static(path.join(__dirname, "../client/build")));
|
|
app.get("*", (req, res) =>
|
|
res.sendFile(path.join(__dirname, "../client/build/index.html"))
|
|
);
|
|
|
|
// Error Handling Middleware
|
|
app.use((err, req, res, next) => {
|
|
console.error("Error:", err.stack);
|
|
res.status(err.status || 500).json({ error: err.message || "Internal Server Error" });
|
|
});
|
|
|
|
// Start Server
|
|
app.listen(PORT, () => {
|
|
console.log(`Server is running at http://localhost:8080`);
|
|
});
|