Skip to content

Added comments #784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,30 @@
# Run

`npm start`

# Changes 4/3/25
- **Updated packages**: Upgraded all dependencies to their latest versions for compatibility and improved functionality.
- **Logout function**: Refactored the `logout` function in `auth.js` to include a callback for `req.logout` (required in Passport v0.6.0+). Ensured the session is properly destroyed using `req.session.destroy`, the session cookie is cleared with `res.clearCookie("connect.sid")`, and the user is redirected to the homepage (`/`).
- **Deleting posts**: Replaced the deprecated `Post.remove` method with `Post.findByIdAndDelete` in `posts.js` for compatibility with Mongoose v7.x. Simplified `Post.findById` by removing unnecessary curly braces and `_id` to streamline the query.
- **Comment creation**: Fixed the comment creation functionality by correcting the `res.redirect` URL in `comments.js` to include the missing `/` between `/post` and the post ID, ensuring proper redirection back to the post page.
- **Passport.js refactor**: Refactored `passport.js` to replace callback-based Mongoose queries (e.g., `User.findOne`) with `async/await` for compatibility with Mongoose v7.x, which no longer supports callbacks. Improved error handling by wrapping queries in `try/catch` blocks for better reliability and debugging.


- **Added a like button for comments**:
- Updated the `comments.js` route file to include a `PUT` route for liking comments (`/likeComment/:id`).
- Added a `likeComment` method in the `commentsController` to increment the `likes` field in the `Comment` model using `findByIdAndUpdate`.
- Updated the `post.ejs` file to include a like button for each comment, which sends a `PUT` request to the server using the `method-override` middleware.

- **Added a delete button for comments**:
- Updated the `comments.js` route file to include a `DELETE` route for deleting comments (`/deleteComment/:id`).
- Added a `deleteComment` method in the `commentsController` to find and delete a comment by its ID using `findById` and `deleteOne`.
- Updated the `post.ejs` file to include a delete button for each comment, which sends a `DELETE` request to the server using the `method-override` middleware.
- Ensured the `postId` is passed as a hidden input in the form to allow redirection back to the correct post page after deletion.

- **Updated deleting comments when deleting posts**:
- deleteMany() is a mongoDB method that is used to delete multiple documents from a collection that match a specified filter. This allows for easy removal of comments when getting rid of a post.

- Added some CSS to make comments nicer to look at.



13 changes: 6 additions & 7 deletions config/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ const mongoose = require("mongoose");

const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.DB_STRING, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true,
});

const conn = await mongoose.connect(process.env.DB_STRING)
//console.log(`MongoDB Connected: ${conn.connection.host}`)
//useNewUrlParser: true, //deprecated next version
//useUnifiedTopology: true, //depreceated next version
//useFindAndModify: false, //outdated
//useCreateIndex: true, //outdated
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (err) {
console.error(err);
Expand Down
41 changes: 23 additions & 18 deletions config/passport.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,43 @@ const User = require("../models/User");

module.exports = function (passport) {
passport.use(
new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (err, user) => {
if (err) {
return done(err);
}
new LocalStrategy({ usernameField: "email" }, async (email, password, done) => {
try {
// Use async/await instead of a callback
const user = await User.findOne({ email: email.toLowerCase() });

if (!user) {
return done(null, false, { msg: `Email ${email} not found.` });
}

if (!user.password) {
return done(null, false, {
msg:
"Your account was registered using a sign-in provider. To enable password login, sign in using a provider, and then set a password under your user profile.",
msg: "Your account was registered using a sign-in provider. To enable password login, sign in using a provider, and then set a password under your user profile.",
});
}
user.comparePassword(password, (err, isMatch) => {
if (err) {
return done(err);
}
if (isMatch) {
return done(null, user);
}

const isMatch = await user.comparePassword(password);
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { msg: "Invalid email or password." });
});
});
}
} catch (err) {
return done(err);
}
})
);

passport.serializeUser((user, done) => {
done(null, user.id);
});

passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user));
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id);
done(null, user);
} catch (err) {
done(err, null);
}
});
};
91 changes: 54 additions & 37 deletions controllers/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,38 @@ exports.postLogin = (req, res, next) => {
})(req, res, next);
};

exports.logout = (req, res) => {
req.logout(() => {
console.log('User has logged out.')
})
req.session.destroy((err) => {
if (err)
console.log("Error : Failed to destroy the session during logout.", err);
req.user = null;
res.redirect("/");
exports.logout = (req, res, next) => {
req.logout((err) => {
if (err) {
console.error("Error during logout:", err);
return next(err);
}
// Destroy the session
req.session.destroy((err) => {
if (err) {
console.error("Error destroying session:", err);
return next(err);
}
// Clear the session cookie
res.clearCookie("connect.sid");
// Redirect to the homepage
res.redirect("/");
});
});
};

// exports.logout = async (req, res) => { //depreceated
// req.logout(() => {
// console.log('User has logged out.')
// })
// req.session.destroy((err) => {
// if (err)
// console.log("Error : Failed to destroy the session during logout.", err);
// req.user = null;
// res.redirect("/");
// });
// };

exports.getSignup = (req, res) => {
if (req.user) {
return res.redirect("/profile");
Expand All @@ -65,7 +85,7 @@ exports.getSignup = (req, res) => {
});
};

exports.postSignup = (req, res, next) => {
exports.postSignup = async(req, res, next) => {
const validationErrors = [];
if (!validator.isEmail(req.body.email))
validationErrors.push({ msg: "Please enter a valid email address." });
Expand All @@ -84,35 +104,32 @@ exports.postSignup = (req, res, next) => {
gmail_remove_dots: false,
});

const user = new User({
userName: req.body.userName,
email: req.body.email,
password: req.body.password,
});
try {
// Check if the user already exists
const existingUser = await User.findOne({ email: req.body.email });
if (existingUser) {
req.flash("errors", { msg: "An account with that email already exists." });
return res.redirect("../signup");
}

// Create a new user
const newUser = new User({
userName: req.body.userName,
email: req.body.email,
password: req.body.password,
});

await newUser.save();

User.findOne(
{ $or: [{ email: req.body.email }, { userName: req.body.userName }] },
(err, existingUser) => {
req.logIn(newUser, (err) => {
if (err) {
return next(err);
}
if (existingUser) {
req.flash("errors", {
msg: "Account with that email address or username already exists.",
});
return res.redirect("../signup");
}
user.save((err) => {
if (err) {
return next(err);
}
req.logIn(user, (err) => {
if (err) {
return next(err);
}
res.redirect("/profile");
});
});
}
);
req.flash("success", { msg: "You have successfully signed up!" });
res.redirect("/profile");
});
} catch (err) {
console.error(err);
res.redirect("/signup");
}
};
57 changes: 57 additions & 0 deletions controllers/comments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const Comment = require("../models/Comment");

module.exports = {
createComment: async (req, res) => {
try {
await Comment.create({
comment: req.body.comment,
likes: 0,
post: req.params.id,
user: req.user.id,
});
console.log("Comment has been added!");
res.redirect("/post/"+req.params.id);
} catch (err) {
console.log(err);
}
},
likeComment: async (req, res) => {
try {
await Comment.findByIdAndUpdate(
req.params.id,
{ $inc: { likes: 1 } }, // Increment the likes field by 1
{ new: true } // Return the updated document
);
console.log("Comment liked!");
res.redirect("/post/"+req.body.postId); // Redirect back to the same page
} catch (err) {
console.error(err);
res.redirect("/post/"+req.body.postId);
}
},
deleteComment: async (req, res) => {
try {
//debugging
console.log("Request Params:", req.params);
console.log("Request Body:", req.body);

const comment = await Comment.findById(req.params.id)

// Check if the comment exists
if (!comment) {
console.error("Comment not found");
return res.redirect(`/post/${req.body.postId}`);
}

// Delete the comment
await Comment.deleteOne({ _id: req.params.id });
console.log("Comment deleted!");

// Redirect back to the post page
res.redirect(`/post/${req.body.postId}`);
} catch (err) {
console.error(err);
res.redirect(`/post/${req.body.postId}`);
}
},
};
24 changes: 21 additions & 3 deletions controllers/posts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const cloudinary = require("../middleware/cloudinary");
const Post = require("../models/Post");
const Comment = require("../models/Comment");


module.exports = {
getProfile: async (req, res) => {
Expand All @@ -21,9 +23,15 @@ module.exports = {
getPost: async (req, res) => {
try {
const post = await Post.findById(req.params.id);
res.render("post.ejs", { post: post, user: req.user });
const comments = await Comment.find({ post: req.params.id })
.populate("user", "userName ") //populate user field with username
.sort({ createdAt: "asc" })
.lean();
res.render("post.ejs", { post: post, user: req.user, comments: comments });

} catch (err) {
console.log(err);
res.redirect("/feed"); //redirect to feed
}
},
createPost: async (req, res) => {
Expand Down Expand Up @@ -62,14 +70,24 @@ module.exports = {
deletePost: async (req, res) => {
try {
// Find post by id
let post = await Post.findById({ _id: req.params.id });
let post = await Post.findById(req.params.id);
// Check if post exists
if (!post) {
console.error("Post not found");
return res.redirect("/profile");
}

// Delete image from cloudinary
await cloudinary.uploader.destroy(post.cloudinaryId);
// Delete all comments associated with the post
await Comment.deleteMany({ post: req.params.id });
// Delete post from db
await Post.remove({ _id: req.params.id });
await Post.findByIdAndDelete(req.params.id);

console.log("Deleted Post");
res.redirect("/profile");
} catch (err) {
console.error("Error deleting post:", err);
res.redirect("/profile");
}
},
Expand Down
27 changes: 27 additions & 0 deletions models/Comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const mongoose = require("mongoose");

const CommentSchema = new mongoose.Schema({
comment: {
type: String,
required: true,
},
likes: {
type: Number,
default: 0,
// required: true,
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: "Post",
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
createdAt: {
type: Date,
default: Date.now,
},
});

module.exports = mongoose.model("Comment", CommentSchema);
Loading