-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 929c0bc
Showing
40 changed files
with
19,010 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
<div align="center"> | ||
<h1>🏕️ YelpCamp 🌲</h1> | ||
</div> | ||
|
||
<div align="center"> | ||
<h2>- Development Process -</h2> | ||
</div> | ||
|
||
## Initial Setup | ||
|
||
- [x] Add Landing Page | ||
- [x] Add Campgrounds Page that lists all campgrounds | ||
|
||
## Each Campground has: | ||
|
||
- [x] Name | ||
- [x] Image | ||
|
||
## Layout and Basic Styling | ||
|
||
- [x] Create our header and footer partials | ||
- [x] Add in Bootstrap | ||
|
||
## Creating New Campgrounds | ||
|
||
- [x] Setup new campground POST route | ||
- [x] Add in body-parser | ||
- [x] Setup route to show form | ||
- [x] Add basic unstyled form | ||
|
||
## Style the campgrounds page | ||
|
||
- [x] Add a better header/title | ||
- [x] Make campgrounds display in a grid | ||
|
||
## Style the Navbar and Form | ||
|
||
- [x] Add a navbar to all templates | ||
- [x] Style the new campground form | ||
|
||
## Add Mongoose | ||
|
||
- [x] Install and configure Mongoose | ||
- [x] Setup campground model | ||
- [x] Use campground model inside of our routes | ||
|
||
## Show Page | ||
|
||
- [x] Review the RESTful routes we've seen so far | ||
- [x] Add description to our campground model | ||
- [x] Show db.collection.drop() | ||
- [x] Add a show route/template | ||
|
||
## Refactor Mongoose Code | ||
|
||
- [x] Create a models directory | ||
- [x] Use module.exports | ||
- [x] Require everything correctly | ||
|
||
## Add Seeds File | ||
|
||
- [x] Add a seeds.js file | ||
- [x] Run the seeds file every time the server starts | ||
|
||
## Add the Comment model | ||
|
||
- [x] Make our errors go away | ||
- [x] Display comments on campground show page | ||
|
||
## Comment New/Create | ||
|
||
- [x] Discuss nested routes | ||
- [x] Add the comment new and create routes | ||
- [x] Add the new comment form | ||
|
||
## Style Show Page | ||
|
||
- [x] Add sidebar to show page | ||
- [x] Display comments nicely | ||
|
||
## Finish Styling Show Page | ||
|
||
- [x] Add public directory | ||
- [x] Add custom stylesheet | ||
|
||
## Auth Pt. 1 - Add User Model | ||
|
||
- [x] Install all packages needed for auth | ||
- [x] Define User model | ||
|
||
## Auth Pt. 2 - Register | ||
|
||
- [x] Cconfigure Passport | ||
- [x] Add register routes | ||
- [x] Add register template | ||
|
||
## Auth Pt. 3 - Login | ||
|
||
- [x] Add login routes | ||
- [x] Add login template | ||
|
||
## Auth Pt. 4 - Logout/Navbar | ||
|
||
- [x] Add logout route | ||
- [x] Prevent user from adding a comment if not signed in | ||
- [x] Add links to navbar | ||
|
||
## Auth Pt. 5 - Show/Hide Links | ||
|
||
- [x] Show/hide auth links in navbar | ||
|
||
## Refactor The Routes | ||
|
||
- [x] Use Express router to reoragnize all routes | ||
|
||
## Users + Comments | ||
|
||
- [x] Associate users and comments | ||
- [x] Save author's name to a comment automatically | ||
|
||
## Users + Campgrounds | ||
|
||
- [x] Prevent an unauthenticated user from creating a campground | ||
- [x] Save username + id to newly created campground | ||
|
||
## Editing Campgrounds | ||
|
||
- [x] Add method override | ||
- [x] Add edit route for campgrounds | ||
- [x] Add link to edit page | ||
- [x] Add update route | ||
|
||
## Deleting Campgrounds | ||
|
||
- [x] Add destroy route | ||
- [x] Add delete button | ||
|
||
## Authorization (permission) | ||
|
||
- [x] User can only edit his/her campgrounds | ||
- [x] User can only delete his/her campgrounds | ||
- [x] Hide/Show edit and delete buttons | ||
|
||
## Editing comments | ||
|
||
- [x] Add edit route for comments | ||
- [x] Add edit template | ||
- [x] Add edit button | ||
- [x] Add update route | ||
|
||
## Deleting comments | ||
|
||
- [x] Add destroy route | ||
- [x] Add delete button | ||
|
||
## Authorization part 2: Comments | ||
|
||
- [x] User can only edit his/her comments | ||
- [x] User can only delete his/her comments | ||
- [x] Hide/Show edit and delete buttons | ||
- [x] Refactor middleware | ||
|
||
## Adding in flash | ||
|
||
- [x] Demo working version | ||
- [x] Install and configure connect-flash | ||
- [x] Add bootstrap alerts to header |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
if(process.env.NODE_ENV !== "production") { | ||
require('dotenv').config(); | ||
} | ||
|
||
const express = require('express'); | ||
const path = require('path'); | ||
const mongoose = require('mongoose'); | ||
const ejsMate = require('ejs-mate'); | ||
const session = require('express-session'); | ||
const flash = require('connect-flash'); | ||
const ExpressError = require('./utils/ExpressError'); | ||
const methodOverride = require('method-override'); | ||
const passport = require('passport'); | ||
const LocalStrategy = require('passport-local'); | ||
const User = require('./models/user'); | ||
const helmet = require('helmet'); | ||
const mongoSanitize = require('express-mongo-sanitize'); | ||
const userRoutes = require('./routes/users'); | ||
const campgroundRoutes = require('./routes/campgrounds'); | ||
const reviewRoutes = require('./routes/reviews'); | ||
const MongoStore = require("connect-mongo"); | ||
const dbUrl = process.env.DB_URL | ||
mongoose.connect(dbUrl, { | ||
useNewUrlParser: true, | ||
useUnifiedTopology: true | ||
}); | ||
|
||
const db = mongoose.connection; | ||
db.once("open", () => { | ||
console.log("Database connected"); | ||
}).on('error', (error) => { | ||
console.log('Connection error', error); | ||
}); | ||
|
||
const app = express(); | ||
|
||
app.engine('ejs', ejsMate) | ||
app.set('view engine', 'ejs'); | ||
app.set('views', path.join(__dirname, 'views')) | ||
|
||
app.use(express.urlencoded({ extended: true })); | ||
app.use(methodOverride('_method')); | ||
app.use(express.static(path.join(__dirname, 'public'))) | ||
app.use(mongoSanitize({ | ||
replaceWith:'_' | ||
})) | ||
|
||
const secret = process.env.SECRET || 'thisshouldbebettersecret'; | ||
|
||
// const store = new MongoStore({ | ||
// url: dbUrl, | ||
// secret: 'thisshouldbebettersecret', | ||
// touchAfter: 24 * 60 * 60 | ||
// }); | ||
|
||
// store.on("error", function(e){ | ||
// console.log("SESSION STORE ERROR",e) | ||
// }) | ||
|
||
const sessionConfig = { | ||
// store, | ||
name:'session', | ||
secret, | ||
resave: false, | ||
saveUninitialized: true, | ||
cookie: { | ||
httpOnly: true, | ||
// secure:true, | ||
expires: Date.now() + 604800000, | ||
maxAge: 604800000 | ||
} | ||
} | ||
app.use(session(sessionConfig)); | ||
app.use(flash()); | ||
|
||
app.use(passport.initialize()); | ||
app.use(passport.session()); | ||
passport.use(new LocalStrategy(User.authenticate())); | ||
|
||
passport.serializeUser(User.serializeUser()); | ||
passport.deserializeUser(User.deserializeUser()); | ||
|
||
app.use((req,res,next)=>{ | ||
res.locals.currentUser = req.user; | ||
res.locals.success = req.flash('success'); | ||
res.locals.error = req.flash('error'); | ||
next(); | ||
}) | ||
|
||
app.use('/',userRoutes); | ||
app.use('/campgrounds',campgroundRoutes) | ||
app.use('/campgrounds/:id/reviews',reviewRoutes) | ||
|
||
app.get('/', (req, res) => { | ||
res.render('home') | ||
}); | ||
|
||
app.all('*', (req, res, next) => { | ||
next(new ExpressError('Page Not Found', 404)) | ||
}) | ||
|
||
app.use((err, req, res, next) => { | ||
const { statusCode = 500 } = err; | ||
if (!err.message) err.message = 'Oh No, Something Went Wrong!' | ||
res.status(statusCode).render('error', { err }) | ||
}) | ||
|
||
const port = process.env.PORT || 3000; | ||
|
||
app.listen(port, () => { | ||
console.log(`Serving on port ${port}`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const cloudinary = require('cloudinary').v2; | ||
const {CloudinaryStorage} = require('multer-storage-cloudinary'); | ||
|
||
cloudinary.config({ | ||
cloud_name: process.env.CLOUDINARY_CLOUD_NAME, | ||
api_key: process.env.CLOUDINARY_KEY, | ||
api_secret: process.env.CLOUDINARY_SECRET | ||
}); | ||
|
||
const storage = new CloudinaryStorage({ | ||
cloudinary, | ||
params:{ | ||
folder: 'YelpCamp', | ||
allowedFormats: ['jpeg','png','jpg'] | ||
} | ||
}); | ||
|
||
module.exports = { | ||
cloudinary, | ||
storage | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
const Campground = require('../models/campground'); | ||
const mbxGeocoding = require("@mapbox/mapbox-sdk/services/geocoding"); | ||
const mapBoxToken = process.env.MAPBOX_TOKEN; | ||
const geocoder = mbxGeocoding({accessToken:mapBoxToken}); | ||
const { cloudinary } = require("../cloudinary"); | ||
|
||
module.exports.index = async (req, res) => { | ||
const campgrounds = await Campground.find({}); | ||
res.render('campgrounds/index', { campgrounds }) | ||
} | ||
|
||
module.exports.renderNewForm = (req, res) => { | ||
res.render('campgrounds/new'); | ||
} | ||
|
||
module.exports.createCampground = async (req, res, next) => { | ||
const geoData = await geocoder.forwardGeocode({ | ||
query: req.body.campground.location, | ||
limit: 1 | ||
}).send() | ||
const campground = new Campground(req.body.campground); | ||
campground.geometry = geoData.body.features[0].geometry; | ||
campground.images = req.files.map(f => ({ url: f.path, filename: f.filename })); | ||
campground.author = req.user._id; | ||
await campground.save(); | ||
console.log(campground); | ||
req.flash('success', 'Successfully made a new campground!'); | ||
res.redirect(`/campgrounds/${campground._id}`) | ||
} | ||
module.exports.showCampground = async (req, res) => { | ||
const campground = await Campground.findById(req.params.id).populate({ | ||
path: 'reviews', | ||
populate: { | ||
path: 'author' | ||
} | ||
}).populate('author'); | ||
if (!campground) { | ||
req.flash('error', 'Cannot find that campground'); | ||
return res.redirect('/campgrounds'); | ||
} | ||
res.render('campgrounds/show', { campground }); | ||
} | ||
|
||
module.exports.renderEditForm = async (req, res) => { | ||
const { id } = req.params; | ||
const campground = await Campground.findById(id) | ||
if (!campground) { | ||
req.flash('error', 'Cannot find that campground'); | ||
return res.redirect('/campgrounds'); | ||
} | ||
res.render('campgrounds/edit', { campground }); | ||
} | ||
|
||
module.exports.updateCampground = async (req, res) => { | ||
const { id } = req.params; | ||
console.log(req.body); | ||
const campground = await Campground.findByIdAndUpdate(id, { ...req.body.campground }); | ||
const imgs = req.files.map(f => ({ url: f.path, filename: f.filename })); | ||
campground.images.push(...imgs); | ||
if (req.body.deleteImages) { | ||
for(let filename of req.body.deleteImages){ | ||
await cloudinary.uploader.destroy(filename); | ||
} | ||
await campground.updateOne({ $pull: { images: { filename: { $in: req.body.deleteImages } } } }); | ||
} | ||
await campground.save(); | ||
req.flash('success', 'Successfully updated campground!') | ||
res.redirect(`/campgrounds/${campground._id}`) | ||
} | ||
|
||
module.exports.deleteCampground = async (req, res) => { | ||
const { id } = req.params; | ||
await Campground.findByIdAndDelete(id); | ||
req.flash('success', 'Successfully deleted campground!'); | ||
res.redirect('/campgrounds'); | ||
} |
Oops, something went wrong.