Skip to content

Commit

Permalink
fullstack template complete
Browse files Browse the repository at this point in the history
  • Loading branch information
leonnoel committed Oct 16, 2022
0 parents commit e80067c
Show file tree
Hide file tree
Showing 30 changed files with 4,472 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.env
.vscode
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: node server.js
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Install

`npm install`

---

# Things to add

- Create a `.env` file in config folder and add the following as `key = value`
- PORT = 2121 (can be any port example: 3000)
- DB_STRING = `your database URI`
- CLOUD_NAME = `your cloudinary cloud name`
- API_KEY = `your cloudinary api key`
- API_SECRET = `your cloudinary api secret`

---

# Run

`npm start`
19 changes: 19 additions & 0 deletions config/database.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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,
});

console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (err) {
console.error(err);
process.exit(1);
}
};

module.exports = connectDB;
41 changes: 41 additions & 0 deletions config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const LocalStrategy = require("passport-local").Strategy;
const mongoose = require("mongoose");
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);
}
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.",
});
}
user.comparePassword(password, (err, isMatch) => {
if (err) {
return done(err);
}
if (isMatch) {
return done(null, user);
}
return done(null, false, { msg: "Invalid email or password." });
});
});
})
);

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

passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user));
});
};
118 changes: 118 additions & 0 deletions controllers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
const passport = require("passport");
const validator = require("validator");
const User = require("../models/User");

exports.getLogin = (req, res) => {
if (req.user) {
return res.redirect("/profile");
}
res.render("login", {
title: "Login",
});
};

exports.postLogin = (req, res, next) => {
const validationErrors = [];
if (!validator.isEmail(req.body.email))
validationErrors.push({ msg: "Please enter a valid email address." });
if (validator.isEmpty(req.body.password))
validationErrors.push({ msg: "Password cannot be blank." });

if (validationErrors.length) {
req.flash("errors", validationErrors);
return res.redirect("/login");
}
req.body.email = validator.normalizeEmail(req.body.email, {
gmail_remove_dots: false,
});

passport.authenticate("local", (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
req.flash("errors", info);
return res.redirect("/login");
}
req.logIn(user, (err) => {
if (err) {
return next(err);
}
req.flash("success", { msg: "Success! You are logged in." });
res.redirect(req.session.returnTo || "/profile");
});
})(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.getSignup = (req, res) => {
if (req.user) {
return res.redirect("/profile");
}
res.render("signup", {
title: "Create Account",
});
};

exports.postSignup = (req, res, next) => {
const validationErrors = [];
if (!validator.isEmail(req.body.email))
validationErrors.push({ msg: "Please enter a valid email address." });
if (!validator.isLength(req.body.password, { min: 8 }))
validationErrors.push({
msg: "Password must be at least 8 characters long",
});
if (req.body.password !== req.body.confirmPassword)
validationErrors.push({ msg: "Passwords do not match" });

if (validationErrors.length) {
req.flash("errors", validationErrors);
return res.redirect("../signup");
}
req.body.email = validator.normalizeEmail(req.body.email, {
gmail_remove_dots: false,
});

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

User.findOne(
{ $or: [{ email: req.body.email }, { userName: req.body.userName }] },
(err, existingUser) => {
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");
});
});
}
);
};
5 changes: 5 additions & 0 deletions controllers/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
getIndex: (req, res) => {
res.render("index.ejs");
},
};
78 changes: 78 additions & 0 deletions controllers/posts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const cloudinary = require("../middleware/cloudinary");
const Post = require("../models/Post");

module.exports = {
getProfile: async (req, res) => {
console.log(req.user)
try {
//Since we have a session each request (req) contains the logged-in users info: req.user
//console.log(req.user) to see everything
//Grabbing just the posts of the logged-in user
const posts = await Post.find({ user: req.user.id });
//Sending post data from mongodb and user data to ejs template
res.render("profile.ejs", { posts: posts, user: req.user });
} catch (err) {
console.log(err);
}
},
getPost: async (req, res) => {
try {
//id parameter comes from the post routes
//router.get("/:id", ensureAuth, postsController.getPost);
//http://localhost:2121/post/631a7f59a3e56acfc7da286f
//id === 631a7f59a3e56acfc7da286f
const post = await Post.findById(req.params.id);
res.render("post.ejs", { post: post, user: req.user});
} catch (err) {
console.log(err);
}
},
createPost: async (req, res) => {
try {
// Upload image to cloudinary
const result = await cloudinary.uploader.upload(req.file.path);

//media is stored on cloudainary - the above request responds with url to media and the media id that you will need when deleting content
await Post.create({
title: req.body.title,
image: result.secure_url,
cloudinaryId: result.public_id,
caption: req.body.caption,
likes: 0,
user: req.user.id,
});
console.log("Post has been added!");
res.redirect("/profile");
} catch (err) {
console.log(err);
}
},
likePost: async (req, res) => {
try {
await Post.findOneAndUpdate(
{ _id: req.params.id },
{
$inc: { likes: 1 },
}
);
console.log("Likes +1");
res.redirect(`/post/${req.params.id}`);
} catch (err) {
console.log(err);
}
},
deletePost: async (req, res) => {
try {
// Find post by id
let post = await Post.findById({ _id: req.params.id });
// Delete image from cloudinary
await cloudinary.uploader.destroy(post.cloudinaryId);
// Delete post from db
await Post.remove({ _id: req.params.id });
console.log("Deleted Post");
res.redirect("/profile");
} catch (err) {
res.redirect("/profile");
}
},
};
9 changes: 9 additions & 0 deletions middleware/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
ensureAuth: function (req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect("/");
}
}
};
11 changes: 11 additions & 0 deletions middleware/cloudinary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const cloudinary = require("cloudinary").v2;

require("dotenv").config({ path: "./config/.env" });

cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET,
});

module.exports = cloudinary;
14 changes: 14 additions & 0 deletions middleware/multer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const multer = require("multer");
const path = require("path");

module.exports = multer({
storage: multer.diskStorage({}),
fileFilter: (req, file, cb) => {
let ext = path.extname(file.originalname);
if (ext !== ".jpg" && ext !== ".jpeg" && ext !== ".png") {
cb(new Error("File type is not supported"), false);
return;
}
cb(null, true);
},
});
35 changes: 35 additions & 0 deletions models/Post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const mongoose = require("mongoose");

const PostSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
image: {
type: String,
require: true,
},
cloudinaryId: {
type: String,
require: true,
},
caption: {
type: String,
required: true,
},
likes: {
type: Number,
required: true,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
createdAt: {
type: Date,
default: Date.now,
},
});

//MongoDB Collection named here - will give lowercase plural of name
module.exports = mongoose.model("Post", PostSchema);
Loading

0 comments on commit e80067c

Please sign in to comment.