diff --git a/app.js b/app.js index 12c54a4..1e13bc0 100644 --- a/app.js +++ b/app.js @@ -1,15 +1,9 @@ require("dotenv").config(); const express = require("express"); const bodyParser = require("body-parser"); -const ejs = require("ejs"); const mongoose = require("mongoose"); -const session = require("express-session"); const passport = require("passport"); -const passportLocalMongoose = require("passport-local-mongoose"); -const findOrCreate = require("mongoose-findorcreate"); -const LocalStrategy = require("passport-local").Strategy; -const GoogleStrategy = require("passport-google-oauth20").Strategy; -const FacebookStrategy = require("passport-facebook").Strategy; +const session = require("express-session"); const app = express(); @@ -29,288 +23,22 @@ app.use( app.use(passport.initialize()); app.use(passport.session()); -mongoose.set('strictQuery', false); - -const userSchema = new mongoose.Schema({ - username: String, - password: String, - googleId: String, - facebookId: String, - secret: [ - { - title: { type: String, required: true }, - upvote: { type: Number, default: 0 }, - downvote: { type: Number, default: 0 }, - } - ], -}); - -userSchema.plugin(passportLocalMongoose); -userSchema.plugin(findOrCreate); - -const User = mongoose.model("User", userSchema); - -passport.use(User.createStrategy()); - -passport.serializeUser(function (user, done) { - done(null, user.id); -}); - -passport.deserializeUser(function (id, done) { - User.findById(id, function (err, user) { - done(err, user); - }); -}); - -passport.use( - new GoogleStrategy( - { - clientID: process.env.GOOGLE_ID, - clientSecret: process.env.GOOGLE_SECRET, - callbackURL: `${process.env.PUBLIC_BASENAME}auth/google/secrets`, - }, - function (accessToken, refreshToken, profile, cb) { - User.findOne({ googleId: profile.id }, (err, existingUser) => { - if (err) { - return cb(err); - } - - if (existingUser) { - console.log("User already exists, return the existing user"); - return cb(null, existingUser); - } - - console.log("User does not exist, create a new one") - const newUser = new User({ googleId: profile.id, username: profile.displayName }); - console.log("id" + newUser.googleId); - console.log("username" + newUser.username); - newUser.save((err, user) => { - if (err) { - console.error('Error saving new user:', err); - return cb(err, null); - } - - console.log('New User saved successfully:', user); - return cb(null, user); - }); - }); - } - ) -); - -passport.use( - new FacebookStrategy( - { - clientID: process.env.FACEBOOK_APP_ID, - clientSecret: process.env.FACEBOOK_APP_SECRET, - callbackURL: `${process.env.PUBLIC_BASENAME}auth/facebook/secrets`, - }, - function (accessToken, refreshToken, profile, cb) { - User.findOne({ facebookId: profile.id }, (err, existingUser) => { - if (err) { - return cb(err); - } - - if (existingUser) { - console.log("User already exists, return the existing user"); - return cb(null, existingUser); - } - - console.log("User does not exist, create a new one") - const newUser = new User({ facebookId: profile.id, username: profile.displayName }); - console.log("id" + newUser.facebookId); - console.log("username" + newUser.username); - newUser.save((err, user) => { - if (err) { - console.error('Error saving new user:', err); - return cb(err, null); - } - - console.log('New User saved successfully:', user); - return cb(null, user); - }); - }); - } - ) -); - -app.get("/", function (req, res) { - res.render("home"); -}); - -app.get( - "/auth/google", - passport.authenticate("google", { scope: ["profile"] }) -); - -app.get( - "/auth/google/secrets", - passport.authenticate("google", { failureRedirect: "/login" }), - function (req, res) { - res.redirect("/secrets"); - } -); - -app.get("/auth/facebook", passport.authenticate("facebook")); - -app.get( - "/auth/facebook/secrets", - passport.authenticate("facebook", { failureRedirect: "/login" }), - function (req, res) { - res.redirect("/secrets"); - } -); - -app.get("/login", function (req, res) { - res.render("login"); -}); +// Import routes +const serverRoutes = require('./routes/server'); +app.use(serverRoutes); -app.get("/about", function (req, res) { - res.render("about"); -}); - -app.get("/contact", function (req, res) { - res.render("contact"); -}); - -app.get("/register", function (req, res) { - res.render("register"); -}); - -app.get("/privacy", function (req, res) { - res.render("privacy"); -}); - -app.post("/register", function (req, res) { - User.register( - { username: req.body.username }, - req.body.password, - function (err, user) { - if (err) { - console.log(err); - res.render("register", { error: err.message }); - } else { - passport.authenticate("local")(req, res, function () { - res.redirect("/login"); - }); - } - } - ); -}); - -app.post("/login", function (req, res, next) { - passport.authenticate("local", function (err, user, info) { - if (err) { - return next(err); - } - if (!user) { - return res.render("login", { error: info.message }); - } - req.logIn(user, function (err) { - if (err) { - return next(err); - } - return res.redirect("/secrets"); - }); - })(req, res, next); -}); - -app.get("/secrets", function (req, res) { - User.find({ secret: { $ne: null } }, function (err, foundUsers) { - if (err) { - console.log(err); - } else { - if (foundUsers) { - res.render("secrets", { - usersWithSecrets: foundUsers, - upvoted: false, - downvoted: false, - }); - } - } - }); -}); - -app.get("/submit-secret-form", function (req, res) { - if (req.isAuthenticated()) { - res.render("secret-form"); - } else { - res.redirect("/login"); - } -}); - -app.post("/submit-secret-form", function (req, res) { - const submittedSecret = req.body.secret; - User.findById(req.user.id, function (err, foundUser) { - if (err) { - console.log(err); - } else { - if (foundUser) { - foundUser.secret.push({ title: submittedSecret }); - - foundUser.save(function (err) { - if (err) { - console.log(err) - } else { - res.redirect("/secrets"); - } - }); - } - } - }); -}); - -app.get("/logout", function (req, res) { - req.logout(function (err) { - if (err) { - console.error('Error during logout:', err); - return res.redirect("/"); - } - res.redirect("/"); - }); -}); - -app.post('/api/votes', async (req, res) => { - try { - const { upvoteCount, downvoteCount, index, username } = req.body; - - const user = await User.findOne({ username }); - - if (!user) { - return res.status(404).json({ error: 'User not found' }); - } - - if (index < 0 || index >= user.secret.length) { - return res.status(400).json({ error: 'Invalid secret index' }); - } - - user.secret[index].upvote = upvoteCount; - user.secret[index].downvote = downvoteCount; - - await user.save(); - - res.json({ message: 'Vote updated successfully', user }); - } catch (error) { - console.error(error); - res.status(500).json({ error: 'Internal server error' }); - } -}); - -app.get('*', (req, res) => { - res.status(404).render("404-page"); -}); - -app.listen(process.env.PORT, () => { - mongoose - .connect(process.env.MONGO_SERVER, { - useNewUrlParser: true, - useUnifiedTopology: true, - }) - .then(() => { - console.log("Database connected successfully"); - }) - .catch((error) => { - console.log("DB connection failed", process.env.MONGO_SERVER); - }); - console.log(`Server is running on ${process.env.PORT}`); +// Connect to MongoDB +mongoose.set('strictQuery', false); +mongoose.connect(process.env.MONGO_SERVER, { + useNewUrlParser: true, + useUnifiedTopology: true, +}).then(() => { + console.log("Database connected successfully"); +}).catch((error) => { + console.log("DB connection failed", process.env.MONGO_SERVER); +}); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server is running on port ${PORT}`); }); diff --git a/controllers/authController.js b/controllers/authController.js new file mode 100644 index 0000000..fdc2852 --- /dev/null +++ b/controllers/authController.js @@ -0,0 +1,60 @@ +const passport = require("passport"); +const User = require("../models/user"); + +exports.getHome = (req, res) => { + res.render("home"); +}; + +exports.getLogin = (req, res) => { + res.render("login"); +}; + +exports.getRegister = (req, res) => { + res.render("register"); +}; + +exports.postRegister = (req, res) => { + User.register({ username: req.body.username }, req.body.password, function (err, user) { + if (err) { + return res.render("register", { error: err.message }); + } + passport.authenticate("local")(req, res, function () { + res.redirect("/login"); + }); + }); +}; + +exports.postLogin = (req, res, next) => { + passport.authenticate("local", function (err, user, info) { + if (err) return next(err); + if (!user) return res.render("login", { error: info.message }); + req.logIn(user, function (err) { + if (err) return next(err); + res.redirect("/secrets"); + }); + })(req, res, next); +}; + +exports.getLogout = (req, res) => { + req.logout((err) => { + if (err) { + console.error('Error during logout:', err); + return res.redirect("/"); + } + res.redirect("/"); + }); +}; + +// Google OAuth +exports.authGoogle = passport.authenticate("google", { scope: ["profile"] }); + +exports.authGoogleSecrets = passport.authenticate("google", { failureRedirect: "/login" }, (req, res) => { + res.redirect("/secrets"); +}); + +// Facebook OAuth +exports.authFacebook = passport.authenticate("facebook"); + +exports.authFacebookSecrets = passport.authenticate("facebook", { failureRedirect: "/login" }, (req, res) => { + res.redirect("/secrets"); +}); diff --git a/controllers/secretController.js b/controllers/secretController.js new file mode 100644 index 0000000..441f3d5 --- /dev/null +++ b/controllers/secretController.js @@ -0,0 +1,31 @@ +const User = require("../models/user"); + +exports.getSecrets = (req, res) => { + User.find({ secret: { $ne: null } }, (err, foundUsers) => { + if (err) { + return res.status(500).send(err); + } + res.render("secrets", { usersWithSecrets: foundUsers, upvoted: false, downvoted: false }); + }); +}; + +exports.getSecretForm = (req, res) => { + if (req.isAuthenticated()) { + res.render("secret-form"); + } else { + res.redirect("/login"); + } +}; + +exports.submitSecretForm = (req, res) => { + const submittedSecret = req.body.secret; + User.findById(req.user.id, (err, foundUser) => { + if (err) return res.status(500).send(err); + + foundUser.secret.push({ title: submittedSecret }); + foundUser.save((err) => { + if (err) return res.status(500).send(err); + res.redirect("/secrets"); + }); + }); +}; diff --git a/controllers/userController.js b/controllers/userController.js new file mode 100644 index 0000000..f6a64a0 --- /dev/null +++ b/controllers/userController.js @@ -0,0 +1,12 @@ +exports.getAbout = (req, res) => { + res.render("about"); + }; + +exports.getContact = (req, res) => { + res.render("contact"); +}; + +exports.getPrivacy = (req, res) => { + res.render("privacy"); +}; + \ No newline at end of file diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..581779d --- /dev/null +++ b/models/user.js @@ -0,0 +1,24 @@ +const mongoose = require("mongoose"); +const passportLocalMongoose = require("passport-local-mongoose"); +const findOrCreate = require("mongoose-findorcreate"); + +const userSchema = new mongoose.Schema({ + username: String, + password: String, + googleId: String, + facebookId: String, + secret: [ + { + title: { type: String, required: true }, + upvote: { type: Number, default: 0 }, + downvote: { type: Number, default: 0 }, + } + ], +}); + +userSchema.plugin(passportLocalMongoose); +userSchema.plugin(findOrCreate); + +const User = mongoose.model("User", userSchema); + +module.exports = User; diff --git a/routes/api.js b/routes/api.js new file mode 100644 index 0000000..1fc874d --- /dev/null +++ b/routes/api.js @@ -0,0 +1,31 @@ +const express = require("express"); +const router = express.Router(); +const User = require("../models/user"); + +router.post('/api/votes', async (req, res) => { + try { + const { upvoteCount, downvoteCount, index, username } = req.body; + + const user = await User.findOne({ username }); + + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + + if (index < 0 || index >= user.secret.length) { + return res.status(400).json({ error: 'Invalid secret index' }); + } + + user.secret[index].upvote = upvoteCount; + user.secret[index].downvote = downvoteCount; + + await user.save(); + + res.json({ message: 'Vote updated successfully', user }); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Internal server error' }); + } +}); + +module.exports = router; diff --git a/routes/server.js b/routes/server.js new file mode 100644 index 0000000..4aabe90 --- /dev/null +++ b/routes/server.js @@ -0,0 +1,35 @@ +const express = require("express"); +const router = express.Router(); + +// Controllers +const authController = require('../controllers/authController'); +const secretController = require('../controllers/secretController'); +const userController = require('../controllers/userController'); + +// Authentication Routes +router.get("/", authController.getHome); +router.get("/login", authController.getLogin); +router.get("/register", authController.getRegister); +router.post("/register", authController.postRegister); +router.post("/login", authController.postLogin); +router.get("/logout", authController.getLogout); + +// Google OAuth Routes +router.get("/auth/google", authController.authGoogle); +router.get("/auth/google/secrets", authController.authGoogleSecrets); + +// Facebook OAuth Routes +router.get("/auth/facebook", authController.authFacebook); +router.get("/auth/facebook/secrets", authController.authFacebookSecrets); + +// Secret Routes +router.get("/secrets", secretController.getSecrets); +router.get("/submit-secret-form", secretController.getSecretForm); +router.post("/submit-secret-form", secretController.submitSecretForm); + +// User Routes (optional, can add more functionalities) +router.get("/about", userController.getAbout); +router.get("/contact", userController.getContact); +router.get("/privacy", userController.getPrivacy); + +module.exports = router;