diff --git a/StackOverFlow_Swiggy i++/.gitignore b/StackOverFlow_Swiggy i++/.gitignore new file mode 100644 index 00000000..ad5e45cc --- /dev/null +++ b/StackOverFlow_Swiggy i++/.gitignore @@ -0,0 +1,3 @@ +node_modules +package.json +package-lock.json \ No newline at end of file diff --git a/StackOverFlow_Swiggy i++/app.js b/StackOverFlow_Swiggy i++/app.js new file mode 100644 index 00000000..c020deaf --- /dev/null +++ b/StackOverFlow_Swiggy i++/app.js @@ -0,0 +1,57 @@ +var express = require('express'), + app = express(), + bodyparser = require('body-parser'), + mongoose = require('mongoose'), + flash = require('connect-flash'), + passport = require('passport'), + localStrategy = require('passport-local'), + methodOverride= require('method-override'), + Question = require("./models/question.js"), + Comment = require("./models/comment.js"), + User = require("./models/user.js"); + + +var commentRoutes = require("./routes/comments.js"), + questionRoutes = require("./routes/questions.js"), + authRoutes = require("./routes/index.js"); + +mongoose.set("useNewUrlParser", true); +mongoose.set("useUnifiedTopology", true); +mongoose.set("useCreateIndex", true); + +mongoose.connect(process.env.DATABASEURL || "mongodb://localhost/stack_overflow"); + +app.use(bodyparser.urlencoded({extended: true})); +app.use(express.static(__dirname + "/public")); +app.set("view engine", "ejs"); +app.use(methodOverride("_method")); +app.use(flash()); +app.locals.moment = require('moment'); + +app.use(require("express-session")({ + secret: "This is the best app", + resave: false, + saveUninitialized: false +})) + +//Passport Configration +app.use(passport.initialize()); +app.use(passport.session()); +passport.use(new localStrategy(User.authenticate())); +passport.serializeUser(User.serializeUser()); +passport.deserializeUser(User.deserializeUser()); + +app.use(function(req, res, next){ + res.locals.currentUser = req.user; + res.locals.error = req.flash("error"); + res.locals.success = req.flash("success"); + next(); +}) + +app.use("/question/:id/comments",commentRoutes); +app.use("/question",questionRoutes); +app.use(authRoutes); + +app.listen(process.env.PORT || 3600,function(req,res){ + console.log("StackOverflow server started"); +}) diff --git a/StackOverFlow_Swiggy i++/middleware/index.js b/StackOverFlow_Swiggy i++/middleware/index.js new file mode 100644 index 00000000..f63de9e5 --- /dev/null +++ b/StackOverFlow_Swiggy i++/middleware/index.js @@ -0,0 +1,58 @@ +var Question = require("../models/question"); +var Comment = require("../models/comment"); + +// all the middleare goes here +var middlewareObj = {}; + +middlewareObj.checkUserOwnership = function(req, res, next) { + if(req.isAuthenticated()){ + Question.findById(req.params.id, function(err, foundQuestion){ + if(err){ + req.flash("error","Question not found"); + res.redirect("back"); + } else { + // does user own the Question? + if(foundQuestion.author.id.equals(req.user._id) || req.user.isAdmin) { + next(); + } else { + req.flash("error","You don't have permission to do that."); + res.redirect("back"); + } + } + }); + } else { + req.flash("error","You need to be logged in to do that") + res.redirect("back"); + } +} + +middlewareObj.checkCommentOwnership = function(req, res, next) { + if(req.isAuthenticated()){ + Comment.findById(req.params.comment_id, function(err, foundComment){ + if(err){ + res.redirect("back"); + } else { + // does user own the comment? + if(foundComment.author.id.equals(req.user._id) || req.user.isAdmin) { + next(); + } else { + req.flash("error","You don't have permission to do that"); + res.redirect("back"); + } + } + }); + } else { + req.flash("error","You need to be logged in to do that"); + res.redirect("back"); + } +} + +middlewareObj.isLoggedIn = function(req, res, next){ + if(req.isAuthenticated()){ + return next(); + } + req.flash("error","You need to be logged in to do that") + res.redirect("/login"); +} + +module.exports = middlewareObj; \ No newline at end of file diff --git a/StackOverFlow_Swiggy i++/models/comment.js b/StackOverFlow_Swiggy i++/models/comment.js new file mode 100644 index 00000000..b91bad88 --- /dev/null +++ b/StackOverFlow_Swiggy i++/models/comment.js @@ -0,0 +1,21 @@ +var mongoose = require("mongoose"); + +var commentSchema = new mongoose.Schema({ + text: String, + createdAt: { type: Date, default: Date.now }, + author: { + id: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + }, + username: String, + }, + likes: [ + { + type: mongoose.Schema.Types.ObjectId, //creating schema in mongo + ref: "User", + }, + ], +}); + +module.exports = mongoose.model("Comment", commentSchema); \ No newline at end of file diff --git a/StackOverFlow_Swiggy i++/models/question.js b/StackOverFlow_Swiggy i++/models/question.js new file mode 100644 index 00000000..54e912a3 --- /dev/null +++ b/StackOverFlow_Swiggy i++/models/question.js @@ -0,0 +1,36 @@ +var mongoose = require("mongoose"); + +var questionSchema = new mongoose.Schema({ + name: String, + description: String, + createdAt: { type: Date, default: Date.now }, + author: { + id: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + }, + username: String, + }, + comments: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: "Comment", + }, + ], + likes: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + }, + ], +}); +const Comment = require("./comment"); +questionSchema.pre("remove", async function () { + await Comment.remove({ + _id: { + $in: this.comments, + }, + }); +}); + +module.exports = mongoose.model("Question", questionSchema); diff --git a/StackOverFlow_Swiggy i++/models/user.js b/StackOverFlow_Swiggy i++/models/user.js new file mode 100644 index 00000000..60531d1e --- /dev/null +++ b/StackOverFlow_Swiggy i++/models/user.js @@ -0,0 +1,18 @@ +var mongoose = require("mongoose"); +var passportLocalMongoose = require("passport-local-mongoose"); + +var userSchema = new mongoose.Schema({ + username: String, + password: String, + avatar: String, + firstName: String, + lastName: String, + email: { type: String, unique: true, required: true }, + points: { type: Number, default: 0 }, + resetPasswordToken: String, + resetPasswordExpires: Date, + isAdmin: { type: Boolean, default: false }, +}); + +userSchema.plugin(passportLocalMongoose); +module.exports = mongoose.model("User", userSchema); \ No newline at end of file diff --git a/StackOverFlow_Swiggy i++/public/stylesheets/landing.css b/StackOverFlow_Swiggy i++/public/stylesheets/landing.css new file mode 100644 index 00000000..706d6ba6 --- /dev/null +++ b/StackOverFlow_Swiggy i++/public/stylesheets/landing.css @@ -0,0 +1,75 @@ +body { + background-color: #000; +} + +#landing-header { + z-index: 1; + position: relative; + text-align: center; + padding-top: 40vh; +} + +#landing-header h1 { + color: #fff; +} + +.slideshow { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 0; + list-style: none; + margin: 0; + padding: 0; +} + +.slideshow li { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background-size: cover; + background-position: 50% 50%; + background-repeat: no-repeat; + opacity: 0; + z-index: 0; + animation: imageAnimation 50s linear infinite; +} + +.slideshow li:nth-child(1) { + background-image: url(https://miro.medium.com/max/1400/1*dZR-6mVLWHoQr7vBIU2-kw.png) +} +.slideshow li:nth-child(2) { + background-image: url(https://image.freepik.com/free-vector/digital-coding-background-with-numbers-zero-one_1017-30363.jpg); + animation-delay: 10s; +} +.slideshow li:nth-child(3) { + background-image: url(https://image.freepik.com/free-photo/abstract-science-background_1048-5811.jpg); + animation-delay: 20s; +} + + +@keyframes imageAnimation { + 0% { + opacity: 0; + animation-timing-function: ease-in; + } + 10% { + opacity: 1; + animation-timing-function: ease-out; + } + 20% { + opacity: 1 + } + 30% { + opacity: 0 + } +} + +/* Older browser support - .no-cssanimations class added by modernizr */ +.no-cssanimations .slideshow li { + opacity: 1; +} \ No newline at end of file diff --git a/StackOverFlow_Swiggy i++/public/stylesheets/main.css b/StackOverFlow_Swiggy i++/public/stylesheets/main.css new file mode 100644 index 00000000..24b38e56 --- /dev/null +++ b/StackOverFlow_Swiggy i++/public/stylesheets/main.css @@ -0,0 +1,15 @@ +.caption { + padding: 9px; +} + +.card{ + padding: 0; +} + +.navbar{ + margin-bottom: 10px; +} + +.deleteform{ + display: inline; +} diff --git a/StackOverFlow_Swiggy i++/routes/comments.js b/StackOverFlow_Swiggy i++/routes/comments.js new file mode 100644 index 00000000..91372667 --- /dev/null +++ b/StackOverFlow_Swiggy i++/routes/comments.js @@ -0,0 +1,133 @@ +var express = require("express"); +var router = express.Router({ mergeParams: true }); +var Question = require("../models/question.js"); +var Comment = require("../models/comment.js"); +var middleware = require("../middleware/index.js"); +var User = require("../models/user.js"); + +//NEW COMMENT page +router.get("/new", middleware.isLoggedIn, function (req, res) { + Question.findById(req.params.id, function (err, foundquestion) { + if (err) { + console.log(err); + } else { + res.render("comments/new", { question: foundquestion }); + } + }); +}); + +//CREATE COMMENT page +router.post("/", middleware.isLoggedIn, function (req, res) { + Question.findById(req.params.id, function (err, question) { + if (err) { + req.flash("error", "Something went wrong"); + console.log(err); + res.redirect("/question"); + } else { + Comment.create(req.body.comment, function (err, comment) { + if (err) { + console.log(err); + } else { + comment.author.id = req.user._id; + comment.author.username = req.user.username; + comment.save(); + console.log(comment); + question.comments.push(comment); + question.save(); + req.flash("success", "Successfully added comment"); + res.redirect("/question/" + question._id); + } + }); + } + }); +}); + +//COMMENT EDIT +router.get( + "/:comment_id/edit", + middleware.checkCommentOwnership, + function (req, res) { + Comment.findById(req.params.comment_id, function (err, foundComment) { + if (err) { + console.log(err); + res.redirect("back"); + } else { + res.render("comments/edit", { + question_id: req.params.id, + comment: foundComment, + }); + } + }); + } +); + +//COMMENT UPDATE +router.put( + "/:comment_id", + middleware.checkCommentOwnership, + function (req, res) { + Comment.findByIdAndUpdate( + req.params.comment_id, + req.body.comment, + function (err, updatedComment) { + if (err) { + res.redirect("back"); + } else { + res.redirect("/question/" + req.params.id); + } + } + ); + } +); + +//like +router.post("/:id", middleware.isLoggedIn, function (req, res) { + Comment.findById(req.params.id, function (err, comment) { + if (err) { + req.flash("error", "Something went wrong"); + console.log(err); + res.redirect("/question"); + } else { + User.findById(req.user._id, function (err, user) { + if (err) { + console.log(err); + } else { + if (comment.likes.includes(user._id)) { + var idx = comment.likes.indexOf(user._id); + comment.likes.splice(idx, 1); + comment.save(); + User.findById(comment.author.id, function (err, author) { + author.points = author.points - 10; + author.save(); + }); + } else { + comment.likes.push(user); + comment.save(); + User.findById(comment.author.id, function (err, author) { + author.points = author.points + 10; + author.save(); + }); + } + } + }); + } + }); +}); + +//COMMENT DESTROY +router.delete( + "/:comment_id", + middleware.checkCommentOwnership, + function (req, res) { + Comment.findByIdAndRemove(req.params.comment_id, function (err) { + if (err) { + res.redirect("back"); + } else { + req.flash("success", "Comment Deleted"); + res.redirect("back"); + } + }); + } +); + +module.exports = router; diff --git a/StackOverFlow_Swiggy i++/routes/index.js b/StackOverFlow_Swiggy i++/routes/index.js new file mode 100644 index 00000000..96a318f4 --- /dev/null +++ b/StackOverFlow_Swiggy i++/routes/index.js @@ -0,0 +1,96 @@ +var express = require("express"); +var router = express.Router(); +var passport = require("passport"); +var User = require("../models/user.js"); +var Question = require("../models/question.js"); +var async = require("async"); +var nodemailer = require("nodemailer"); +var crypto = require("crypto"); + +router.get("/", function (req, res) { + res.render("landing"); +}); + +//REGISTER +router.get("/register", function (req, res) { + res.render("register", { page: "register" }); +}); + +router.post("/register", function (req, res) { + var newUser = new User({ + username: req.body.username, + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + //avatar: req.body.avatar, + }); + if (req.body.admincode === "secretcode123") { + newUser.isAdmin = true; + } + User.register(newUser, req.body.password, function (err, user) { + if (err) { + console.log(err); + return res.render("register", { error: err.message }); + } else { + passport.authenticate("local")(req, res, function () { + req.flash("success", "Welcome To StackOverflow " + user.username); + res.redirect("/question"); + }); + } + }); +}); + +//LOGIN +router.get("/login", function (req, res) { + res.render("login", { page: "login" }); +}); + +router.post("/login", function (req, res, next) { + console.log(res.body); + passport.authenticate("local", { + successRedirect: "/question", + failureRedirect: "/login", + failureFlash: true, + successFlash: "Welcome to StackOverflow, " + req.body.username + "!", + })(req, res); +}); + +//LOGOUT +router.get("/logout", function (req, res) { + req.logout(); + req.flash("success", "Logged you out!!"); + res.redirect("/question"); +}); + +function isLoggedIn(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } + res.redirect("/login"); +} + +//USER'S PROFILE +router.get("/users/:id", function (req, res) { + User.findById(req.params.id, function (err, foundUser) { + if (err) { + req.flash("error", "Something Went Wrong"); + res.redirect("/"); + } + Question.find() + .where("author.id") + .equals(foundUser._id) + .exec(function (err, questions) { + if (err) { + req.flash("error", "Something Went Wrong"); + res.redirect("/"); + } else { + res.render("users/show", { + user: foundUser, + questions: questions, + }); + } + }); + }); +}); + +module.exports = router; diff --git a/StackOverFlow_Swiggy i++/routes/questions.js b/StackOverFlow_Swiggy i++/routes/questions.js new file mode 100644 index 00000000..f0f2abcb --- /dev/null +++ b/StackOverFlow_Swiggy i++/routes/questions.js @@ -0,0 +1,188 @@ +var express = require("express"); +var router = express.Router(); +var Question = require("../models/question.js"); +var middleware = require("../middleware/index.js"); +var User = require("../models/user.js"); +var { v4: uuid } = require("uuid"); +//=================== +//QUESTION ROUTES +//=================== + + +//INDEX Page + +router.get("/json", function (req, res) { + Question.find({}, function (err, questions) { + + if (err) { + console.log(err); + } else { + res.send({ question: questions }); + } + }); +}); + +router.get("/", function (req, res) { + + Question.find({}, function (err, allquestion) { + console.log(allquestion); + if (err) { + console.log(err); + } else { + res.render("questions/index", { + question: allquestion, + page: "question", + }); + } + }); +}); + +//CREATE + +router.post("/", middleware.isLoggedIn, function (req, res) { + var name = req.body.name; + var desc = req.body.description; + var author = { + id: req.user._id.toString(), + username: req.user.username, + }; + var newquestion = { + name: name, + description: desc, + author: author, + + likes: [], + comments: [], + + }; + + + Question.create(newquestion, function (err, newlycreated) { + if (err) { + console.log(err); + } else { + res.redirect("/question"); + } + }); +}); + +//like +router.post("/:id", middleware.isLoggedIn, function (req, res) { + Question.findById(req.params.id, function (err, question) { + if (err) { + req.flash("error", "Something went wrong"); + console.log(err); + res.redirect("/question"); + } else { + User.findById(req.user._id, function (err, user) { + if (err) { + console.log(err); + } else { + console.log(user); + if (question.likes.includes(user._id)) { + var idx = question.likes.indexOf(user._id); + question.likes.splice(idx, 1); + question.save(); + User.findById(question.author.id, function (err, author) { + author.points = author.points - 10; + if (author.points < 0) { + author.points = 0; + } + author.save(); + + console.log(author); + }); + + + } else { + question.likes.push(user); + question.save(); + User.findById(question.author.id, function (err, author) { + if (author.points < 0) { + author.points = 0; + } + author.points = author.points + 10; + author.save(); + + console.log(author); + }); + + + } + } + }); + } + }); +}); + +//NEW + +router.get("/new", middleware.isLoggedIn, function (req, res) { + res.render("questions/new.ejs"); +}); + +//SHOW +router.get("/:id/json", function (req, res) { + + Question.findById(req.params.id) + .populate("comments") + .exec(function (err, foundquestion) { + if (err) { + console.log(err); + } else { + res.send({ question: foundquestion }); + } + }); +}); + +router.get("/:id", function (req, res) { + + Question.findById(req.params.id) + .populate("comments") + .exec(function (err, foundquestion) { + if (err) { + console.log(err); + } else { + res.render("questions/show.ejs", { question: foundquestion }); + } + }); +}); + +// EDIT ROUTES +router.get("/:id/edit", function (req, res) { + + Question.findById(req.params.id, function (err, foundquestion) { + res.render("questions/edit", { question: foundquestion }); + }); +}); + +router.put("/:id", function (req, res) { + + + Question.findByIdAndUpdate( + req.params.id, + req.body.question, + function (err, updatedQuestion) { + if (err) { + res.redirect("/questions"); + } else { + res.redirect("/question/" + req.params.id); + } + } + ); +}); + +//DESTROY ROUTES + +router.delete("/:id", function (req, res) { + + Question.findByIdAndRemove(req.params.id, function (err) { + if (err) { + res.redirect("/question"); + } else { + res.redirect("/question"); + } + }); +}); + +module.exports = router; diff --git a/StackOverFlow_Swiggy i++/seeds.js b/StackOverFlow_Swiggy i++/seeds.js new file mode 100644 index 00000000..b7bb27e0 --- /dev/null +++ b/StackOverFlow_Swiggy i++/seeds.js @@ -0,0 +1,64 @@ +var mongoose = require("mongoose"); +var Question = require("./models/question"); +var Comment = require("./models/comment"); + +var data = [ + { + name: "Cloud's Rest", + image: "https://farm4.staticflickr.com/3795/10131087094_c1c0a1c859.jpg", + description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" + }, + { + name: "Desert Mesa", + image: "https://farm6.staticflickr.com/5487/11519019346_f66401b6c1.jpg", + description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" + }, + { + name: "Canyon Floor", + image: "https://farm1.staticflickr.com/189/493046463_841a18169e.jpg", + description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" + } +] + +function seedDB(){ + //Remove all questions + Question.remove({}, function(err){ + if(err){ + console.log(err); + } + console.log("removed questions!"); + Comment.remove({}, function(err) { + if(err){ + console.log(err); + } + console.log("removed comments!"); + //add a few questions + data.forEach(function(seed){ + Question.create(seed, function(err, question){ + if(err){ + console.log(err) + } else { + console.log("added a question"); + //create a comment + Comment.create( + { + text: "This place is great, but I wish there was internet", + author: "Homer" + }, function(err, comment){ + if(err){ + console.log(err); + } else { + question.comments.push(comment); + question.save(); + console.log("Created new comment"); + } + }); + } + }); + }); + }); + }); + //add a few comments +} + +module.exports = seedDB; \ No newline at end of file diff --git a/StackOverFlow_Swiggy i++/views/comments/edit.ejs b/StackOverFlow_Swiggy i++/views/comments/edit.ejs new file mode 100644 index 00000000..6d00d710 --- /dev/null +++ b/StackOverFlow_Swiggy i++/views/comments/edit.ejs @@ -0,0 +1,22 @@ +<% include ../partials/header %> +
Ask anything and get best possible solution! Be curious!.
++ Ask a question +
+<%= question.description %>
++ Submitted by: + <%= question.author.username %>, <%= + moment(question.createdAt).fromNow() %> +
+ <% if(currentUser && question.author.username == currentUser.username || + currentUser && currentUser.points>30){ %> + + Edit + + + <% } %> + + +<%= comment.text %>
+ <% if(currentUser && comment.author.username === currentUser.username || + currentUser && currentUser.isAdmin){ %> + + Edit + <% } %> + +