diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1823865 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +npm-debug.log +queries.js +backup.handlebars diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..e1d4131 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node app.js diff --git a/README.md b/README.md index 7513987..ed10373 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # assignment_thoreddit A social news web application for Viking thunder Gods + +Name: Thomas Hauge diff --git a/app.js b/app.js new file mode 100644 index 0000000..3e53c35 --- /dev/null +++ b/app.js @@ -0,0 +1,83 @@ +const express = require('express'); +const app = express(); + +// Body Parser +const bodyParser = require('body-parser'); +app.use(bodyParser.urlencoded({ extended: true })); + +// Session/Cookies +const cookieSession = require('cookie-session'); +app.use( + cookieSession({ + name: 'session', + keys: ['asdf1234'] + }) +); + +app.use((req, res, next) => { + res.locals.session = req.session; + res.locals.currentUser = req.session.currentUser; + next(); +}); + +// Method Override +const methodOverride = require('method-override'); +const getPostSupport = require('express-method-override-get-post-support'); +app.use(methodOverride(getPostSupport.callback, getPostSupport.options)); + +// Referrer +app.use((req, res, next) => { + req.session.backUrl = req.header('Referer') || '/'; + next(); +}); + +// Logging +const morgan = require('morgan'); +app.use(morgan('tiny')); + +// Mongoose +const mongoose = require('mongoose'); +app.use((req, res, next) => { + if (mongoose.connection.readyState) { + next(); + } else { + require('./mongo')().then(() => next()); + } +}); + +// Routes +const sessionsRoutes = require('./controllers/sessions')(app); +const usersRoutes = require('./controllers/users'); +const postsRoutes = require('./controllers/posts'); +const commentsRoutes = require('./controllers/comments'); + +app.use('/', sessionsRoutes); +app.use('/users', usersRoutes); +app.use('/posts', postsRoutes); +app.use('/comments', commentsRoutes); + +// Template Engine +const expressHandlebars = require('express-handlebars'); + +const hbs = expressHandlebars.create({ + partialsDir: 'views/', + defaultLayout: 'application' +}); + +app.engine('handlebars', hbs.engine); +app.set('view engine', 'handlebars'); + +// Server +const port = process.env.PORT || process.argv[2] || 3000; +const host = 'localhost'; + +let args; +process.env.NODE_ENV === 'production' ? (args = [port]) : (args = [port, host]); + +args.push(() => { + console.log(`Listening: http://${host}:${port}`); +}); + +app.listen.apply(app, args); + +module.exports = app; diff --git a/config/mongo.json b/config/mongo.json new file mode 100644 index 0000000..cff3d4f --- /dev/null +++ b/config/mongo.json @@ -0,0 +1,13 @@ +{ + "development": { + "database": "assignment_thoreddit_development", + "host": "localhost" + }, + "test": { + "database": "assignment_thoreddit_test", + "host": "localhost" + }, + "production": { + "use_env_variable": "MONGODB_URI" + } +} diff --git a/controllers/comments.js b/controllers/comments.js new file mode 100644 index 0000000..59ff446 --- /dev/null +++ b/controllers/comments.js @@ -0,0 +1,220 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const models = require('./../models'); + +const router = express.Router(); +const User = mongoose.model('User'); +const Post = mongoose.model('Post'); +const Comment = mongoose.model('Comment'); +const Vote = mongoose.model('Vote'); + +// New +router.get('/:id/new', (req, res) => { + let parentType; + Comment.findById(req.params.id).then(comment => { + if (comment) { + parentType = 'comment'; + res.render('comments/new', { comment, parentType }); + } else { + Post.findById(req.params.id).then(post => { + let comment = { + body: post.body, + author: post.author, + post: post.id + }; + parentType = 'post'; + res.render('comments/new', { comment, parentType }); + }); + } + }); +}); + +// Create +router.post('/', (req, res) => { + let comment; + + User.findOne({ username: req.session.currentUser.username }).then(user => { + if (req.body.comment.parent) { + comment = new Comment({ + body: req.body.comment.body, + author: user, + post: req.body.comment.post, + parent: req.body.comment.parent, + score: 0 + }); + } else { + comment = new Comment({ + body: req.body.comment.body, + author: user, + post: req.body.comment.post, + score: 0 + }); + } + + comment + .save() + .then(comment => { + if (req.body.comment.parent) { + return Comment.findByIdAndUpdate(req.body.comment.parent, { + $push: { children: comment } + }); + } + }) + .then(() => { + res.redirect(`/posts/${req.body.comment.post}`); + }) + .catch(e => res.status(500).send(e.stack)); + }); +}); + +// Upvote +router.get( + '/:id/up', + (req, res, next) => { + Vote.findOne({ + user: req.session.currentUser.id, + comment: req.params.id + }) + .then(vote => { + if (vote) { + if (vote.count === 1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + comment: req.params.id, + count: 0 + }) + .then(() => { + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: -1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === 0) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + comment: req.params.id, + count: 1 + }) + .then(() => { + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: 1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === -1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + comment: req.params.id, + count: 1 + }) + .then(() => { + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: 2 } + }); + }) + .then(() => { + next(); + }); + } + } else { + const vote = new Vote({ + user: req.session.currentUser.id, + comment: req.params.id, + count: 1 + }); + + vote.save().then(() => {}); + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: 1 } + }); + } + }) + .then(() => { + next(); + }); + }, + (req, res) => { + res.redirect('back'); + } +); + +// Downvote +router.get( + '/:id/down', + (req, res, next) => { + Vote.findOne({ + user: req.session.currentUser.id, + comment: req.params.id + }) + .then(vote => { + if (vote) { + if (vote.count === -1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + comment: req.params.id, + count: 0 + }) + .then(() => { + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: 1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === 0) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + comment: req.params.id, + count: -1 + }) + .then(() => { + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: -1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === 1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + comment: req.params.id, + count: -1 + }) + .then(() => { + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: -2 } + }); + }) + .then(() => { + next(); + }); + } + } else { + const vote = new Vote({ + user: req.session.currentUser.id, + comment: req.params.id, + count: -1 + }); + + vote.save().then(() => {}); + return Comment.findByIdAndUpdate(req.params.id, { + $inc: { score: -1 } + }); + } + }) + .then(() => { + next(); + }); + }, + (req, res) => { + res.redirect('back'); + } +); + +module.exports = router; diff --git a/controllers/posts.js b/controllers/posts.js new file mode 100644 index 0000000..dd92c70 --- /dev/null +++ b/controllers/posts.js @@ -0,0 +1,272 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const models = require('./../models'); +const { formatPosts } = require('./../helpers/post-helper'); + +const router = express.Router(); +const User = mongoose.model('User'); +const Post = mongoose.model('Post'); +const Comment = mongoose.model('Comment'); +const Vote = mongoose.model('Vote'); + +// Index +router.get('/', (req, res) => { + const user = req.session.currentUser.id; + Post.find() + .populate('author') + .then(posts => { + const formattedPosts = formatPosts(posts, user); + res.render('posts/index', { + posts: formattedPosts + }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// New +router.get('/new', (req, res) => { + res.render('posts/new'); +}); + +// Edit +router.get('/:id/edit', (req, res) => { + Post.findById(req.params.id) + .then(post => { + if (post) { + res.render('posts/edit', { post }); + } else { + res.send(404); + } + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Show +router.get('/:id', (req, res) => { + const p1 = Post.findById(req.params.id).populate('author'); + const p2 = Comment.find({ + post: req.params.id + }).populate([ + { + path: 'children', + populate: [ + { + path: 'children', + populate: { + path: 'author' + } + }, + { + path: 'author' + } + ] + }, + { + path: 'author' + } + ]); + + Promise.all([p1, p2]) + .then(values => { + const post = values[0]; + const comments = values[1]; + res.render('posts/show', { post, comments }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Create +router.post('/', (req, res) => { + User.findOne({ username: req.session.currentUser.username }).then(user => { + const post = new Post({ + title: req.body.post.title, + body: req.body.post.body, + author: user, + score: 0 + }); + + post + .save() + .then(post => { + res.redirect(`/posts/${post.id}`); + }) + .catch(e => res.status(500).send(e.stack)); + }); +}); + +// Update +router.put('/:id', (req, res) => { + const postParams = req.body.post; + + Post.findByIdAndUpdate(req.params.id, { + title: postParams.title, + body: postParams.body + }) + .then(post => { + req.method = 'GET'; + res.redirect(`/posts/${post.id}`); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Delete +router.delete('/:id', (req, res) => { + Post.findByIdAndRemove(req.params.id) + .then(() => { + req.method = 'GET'; + res.redirect('/posts'); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Upvote +router.get( + '/:id/up', + (req, res, next) => { + Vote.findOne({ + user: req.session.currentUser.id, + post: req.params.id + }) + .then(vote => { + if (vote) { + if (vote.count === 1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + post: req.params.id, + count: 0 + }) + .then(() => { + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: -1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === 0) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + post: req.params.id, + count: 1 + }) + .then(() => { + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: 1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === -1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + post: req.params.id, + count: 1 + }) + .then(() => { + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: 2 } + }); + }) + .then(() => { + next(); + }); + } + } else { + const vote = new Vote({ + user: req.session.currentUser.id, + post: req.params.id, + count: 1 + }); + + vote.save().then(() => {}); + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: 1 } + }); + } + }) + .then(() => { + next(); + }); + }, + (req, res) => { + res.redirect('back'); + } +); + +// Downvote +router.get( + '/:id/down', + (req, res, next) => { + Vote.findOne({ + user: req.session.currentUser.id, + post: req.params.id + }) + .then(vote => { + if (vote) { + if (vote.count === -1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + post: req.params.id, + count: 0 + }) + .then(() => { + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: 1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === 0) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + post: req.params.id, + count: -1 + }) + .then(() => { + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: -1 } + }); + }) + .then(() => { + next(); + }); + } else if (vote.count === 1) { + Vote.findByIdAndUpdate(vote.id, { + user: req.session.currentUser.id, + post: req.params.id, + count: -1 + }) + .then(() => { + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: -2 } + }); + }) + .then(() => { + next(); + }); + } + } else { + const vote = new Vote({ + user: req.session.currentUser.id, + post: req.params.id, + count: -1 + }); + + vote.save().then(() => {}); + return Post.findByIdAndUpdate(req.params.id, { + $inc: { score: -1 } + }); + } + }) + .then(() => { + next(); + }); + }, + (req, res) => { + res.redirect('back'); + } +); + +module.exports = router; diff --git a/controllers/sessions.js b/controllers/sessions.js new file mode 100644 index 0000000..53833bf --- /dev/null +++ b/controllers/sessions.js @@ -0,0 +1,65 @@ +const url = require('url'); +const express = require('express'); +const mongoose = require('mongoose'); +const models = require('./../models'); + +const router = express.Router(); +const User = mongoose.model('User'); + +module.exports = app => { + // Auth + app.use((req, res, next) => { + const reqUrl = url.parse(req.url); + if ( + !req.session.currentUser && + !['/', '/login', '/sessions'].includes(reqUrl.pathname) + ) { + res.redirect('/login'); + } else { + next(); + } + }); + + // New + const onNew = (req, res) => { + if (req.session.currentUser) { + res.redirect('/users'); + } else { + res.render('sessions/new'); + } + }; + router.get('/', onNew); + router.get('/login', onNew); + + // Create + router.post('/sessions', (req, res) => { + User.findOne({ + username: req.body.username, + email: req.body.email + }) + .then(user => { + if (user) { + req.session.currentUser = { + username: user.username, + email: user.email, + id: user.id, + _id: user._id + }; + res.redirect('/users'); + } else { + res.redirect('/login'); + } + }) + .catch(e => res.status(500).send(e.stack)); + }); + + // Destroy + const onDestroy = (req, res) => { + req.session.currentUser = null; + res.redirect('/login'); + }; + router.get('/logout', onDestroy); + router.delete('/logout', onDestroy); + + return router; +}; diff --git a/controllers/users.js b/controllers/users.js new file mode 100644 index 0000000..adebf52 --- /dev/null +++ b/controllers/users.js @@ -0,0 +1,87 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const models = require('./../models'); + +const router = express.Router(); +const User = mongoose.model('User'); + +// Index +router.get('/', (req, res) => { + User.find() + .then(users => { + res.render('users/index', { users }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// New +router.get('/new', (req, res) => { + res.render('users/new'); +}); + +// Edit +router.get('/:id/edit', (req, res) => { + User.findById(req.params.id) + .then(user => { + res.render('users/edit', { user }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Show +router.get('/:id', (req, res) => { + User.findById(req.params.id) + .then(user => { + res.render('users/show', { user }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Create +router.post('/', (req, res) => { + const user = new User({ + fname: req.body.user.fname, + lname: req.body.user.lname, + username: req.body.user.username, + email: req.body.user.email + }); + + user + .save() + .then(user => { + res.redirect(`/users/${user.id}`); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Update +router.put('/:id', (req, res) => { + const userParams = { + fname: req.body.user.fname, + lname: req.body.user.lname, + username: req.body.user.username, + email: req.body.user.email + }; + + User.findByIdAndUpdate(req.params.id, userParams) + .then(user => { + res.redirect(`/users/${user.id}`); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +// Destroy +router.delete('/:id', (req, res) => { + const currentUser = req.session.currentUser; + User.findByIdAndRemove(req.params.id) + .then(() => { + if (currentUser.id === req.params.id) { + res.redirect('/logout'); + } else { + res.redirect('/users'); + } + }) + .catch(e => res.status(500).send(e.stack)); +}); + +module.exports = router; diff --git a/helpers/post-helper.js b/helpers/post-helper.js new file mode 100644 index 0000000..0773254 --- /dev/null +++ b/helpers/post-helper.js @@ -0,0 +1,16 @@ +const formatPosts = (posts, user) => { + let formattedPosts = posts; + formattedPosts.forEach(post => { + post.editable = []; + post.postedAt = post.createdAt.toString().slice(0, 24); + if (post.body.toString().length > 25) { + post.body = post.body.toString().slice(0, 50) + '[...]'; + } + if (post.author.id === user) { + post.editable.push([true]); + } + }); + return formattedPosts; +}; + +module.exports = { formatPosts }; diff --git a/models/comment.js b/models/comment.js new file mode 100644 index 0000000..9e46d9c --- /dev/null +++ b/models/comment.js @@ -0,0 +1,23 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const Commentable = require('./commentable'); + +const CommentSchema = new Schema( + { + post: { + type: Schema.Types.ObjectId, + ref: 'Post' + }, + parent: { + type: Schema.Types.ObjectId, + ref: 'Comment' + } + }, + { + discriminatorKey: 'kind' + } +); + +const Comment = Commentable.discriminator('Comment', CommentSchema); + +module.exports = Comment; diff --git a/models/commentable.js b/models/commentable.js new file mode 100644 index 0000000..fd53b73 --- /dev/null +++ b/models/commentable.js @@ -0,0 +1,27 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const CommentableSchema = new Schema( + { + body: String, + score: Number, + author: { + type: Schema.Types.ObjectId, + ref: 'User' + }, + children: [ + { + type: Schema.Types.ObjectId, + ref: 'Comment' + } + ] + }, + { + timestamps: true, + discriminatorKey: 'kind' + } +); + +const Commentable = mongoose.model('Commentable', CommentableSchema); + +module.exports = Commentable; diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..11d050c --- /dev/null +++ b/models/index.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); +const bluebird = require('bluebird'); + +mongoose.Promise = bluebird; + +let models = {}; + +models.User = require('./user'); +models.Post = require('./post'); +models.Comment = require('./comment'); +models.Vote = require('./vote'); + +module.exports = models; diff --git a/models/post.js b/models/post.js new file mode 100644 index 0000000..6c54458 --- /dev/null +++ b/models/post.js @@ -0,0 +1,16 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const Commentable = require('./commentable'); + +const PostSchema = new Schema( + { + title: String + }, + { + discriminatorKey: 'kind' + } +); + +const Post = Commentable.discriminator('Post', PostSchema); + +module.exports = Post; diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..807a277 --- /dev/null +++ b/models/user.js @@ -0,0 +1,18 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const UserSchema = new Schema( + { + fname: String, + lname: String, + username: String, + email: String + }, + { + timestamps: true + } +); + +const User = mongoose.model('User', UserSchema); + +module.exports = User; diff --git a/models/vote.js b/models/vote.js new file mode 100644 index 0000000..87b4cc1 --- /dev/null +++ b/models/vote.js @@ -0,0 +1,22 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const VoteSchema = new Schema({ + user: { + type: Schema.Types.ObjectId, + ref: 'User' + }, + post: { + type: Schema.Types.ObjectId, + ref: 'Post' + }, + comment: { + type: Schema.Types.ObjectId, + ref: 'Comment' + }, + count: Number +}); + +const Vote = mongoose.model('Vote', VoteSchema); + +module.exports = Vote; diff --git a/mongo.js b/mongo.js new file mode 100644 index 0000000..9e9db31 --- /dev/null +++ b/mongo.js @@ -0,0 +1,10 @@ +const mongoose = require('mongoose'); +const env = process.env.NODE_ENV || 'development'; +const config = require('./config/mongo')[env]; + +module.exports = () => { + const envUrl = process.env[config.use_env_variable]; + const localUrl = `mongodb://${config.host}/${config.database}`; + const mongoUrl = envUrl ? envUrl : localUrl; + return mongoose.connect(mongoUrl); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..dea8c19 --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "assignment_thoreddit", + "version": "1.0.0", + "description": "A social news web application for Viking thunder Gods", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "which nodemon > /dev/null && nodemon app.js || node app.js", + "console": "node repl.js", + "c": "node repl.js", + "seed": "node seeds", + "seeds": "node seeds" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/thomahau/assignment_thoreddit.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/thomahau/assignment_thoreddit/issues" + }, + "homepage": "https://github.com/thomahau/assignment_thoreddit#readme", + "dependencies": { + "bluebird": "^3.5.1", + "body-parser": "^1.18.2", + "cookie-session": "^2.0.0-beta.3", + "express": "^4.16.2", + "express-handlebars": "^3.0.0", + "express-method-override-get-post-support": "^1.0.0", + "faker": "^4.1.0", + "method-override": "^2.3.10", + "mongoose": "^4.13.6", + "mongooseeder": "^2.0.5", + "morgan": "^1.9.0", + "voca": "^1.3.1" + } +} diff --git a/repl.js b/repl.js new file mode 100644 index 0000000..539cffe --- /dev/null +++ b/repl.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); +const repl = require('repl').start({}); +const models = require('./models'); + +require('./mongo')().then(() => { + repl.context.models = models; + + Object.keys(models).forEach(modelName => { + repl.context[modelName] = mongoose.model(modelName); + }); + + repl.context.lg = data => console.log(data); +}); diff --git a/seeds/index.js b/seeds/index.js new file mode 100644 index 0000000..5d2676f --- /dev/null +++ b/seeds/index.js @@ -0,0 +1,58 @@ +const mongoose = require('mongoose'); +const mongooseeder = require('mongooseeder'); +const faker = require('faker'); +const voca = require('voca'); +const models = require('./../models'); +const env = process.env.NODE_ENV || 'development'; +const config = require('./../config/mongo')[env]; + +const { User } = models; +const MULTIPLIER = 1; + +const seeds = () => { + // Users + console.log('Creating Users'); + const users = []; + for (let i = 0; i < MULTIPLIER * 5; i++) { + const user = new User({ + fname: 'Foo', + lname: 'Bar', + username: `foobar${i}`, + email: `foobar${i}@gmail.com` + }); + users.push(user); + } + // Posts + // console.log('Creating Posts'); + // const posts = []; + // for (let i = 0; i < MULTIPLIER * 5; i++) { + // const post = new Post({ + // title: + // body: + // + // }) + // } + + // Finish + console.log('Saving...'); + const promises = []; + [users].forEach(collection => { + collection.forEach(model => { + promises.push(model.save()); + }); + }); + return Promise.all(promises); +}; + +const mongodbUrl = + process.env.NODE_ENV === 'production' + ? process.env[config.use_env_variable] + : `mongodb://${config.host}/${config.database}`; + +mongooseeder.seed({ + mongodbUrl: mongodbUrl, + seeds: seeds, + clean: true, + models: models, + mongoose: mongoose +}); diff --git a/views/comments/new.handlebars b/views/comments/new.handlebars new file mode 100644 index 0000000..65f24db --- /dev/null +++ b/views/comments/new.handlebars @@ -0,0 +1,19 @@ + + +
+
+ + +
+ + + + +
+ +
+
diff --git a/views/layouts/application.handlebars b/views/layouts/application.handlebars new file mode 100644 index 0000000..f82289c --- /dev/null +++ b/views/layouts/application.handlebars @@ -0,0 +1,23 @@ + + + + + + + + Thoreddit + + + + + + + + + + {{> shared/_nav }} +
+ {{{ body }}} +
+ + diff --git a/views/posts/edit.handlebars b/views/posts/edit.handlebars new file mode 100644 index 0000000..aee1998 --- /dev/null +++ b/views/posts/edit.handlebars @@ -0,0 +1,21 @@ + + +
+ + +
+ + +
+ +
+ + +
+ +
+ +
+
diff --git a/views/posts/index.handlebars b/views/posts/index.handlebars new file mode 100644 index 0000000..e945b41 --- /dev/null +++ b/views/posts/index.handlebars @@ -0,0 +1,47 @@ + + +{{#if posts.length }} + + + + + + + + + + + + + {{#each posts as |post| }} + + + + + + {{#if post.editable}} + + + {{/if}} + + {{/each }} + +
Posted AtTitleBodyUsername
+ {{ post.postedAt }} + + {{ post.title }} + + {{ post.body }} + + {{ post.author.username }} + + Edit + + Delete +
+{{else }} +

No posts

+{{/if }} diff --git a/views/posts/new.handlebars b/views/posts/new.handlebars new file mode 100644 index 0000000..9c8e59a --- /dev/null +++ b/views/posts/new.handlebars @@ -0,0 +1,19 @@ + + +
+
+ + +
+ +
+ + +
+ +
+ +
+
diff --git a/views/posts/show.handlebars b/views/posts/show.handlebars new file mode 100644 index 0000000..cddcd66 --- /dev/null +++ b/views/posts/show.handlebars @@ -0,0 +1,60 @@ + diff --git a/views/sessions/new.handlebars b/views/sessions/new.handlebars new file mode 100644 index 0000000..eafe41e --- /dev/null +++ b/views/sessions/new.handlebars @@ -0,0 +1,17 @@ + + +
+
+ + +
+
+ + +
+
+ +
+
diff --git a/views/shared/_nav.handlebars b/views/shared/_nav.handlebars new file mode 100644 index 0000000..7af2b96 --- /dev/null +++ b/views/shared/_nav.handlebars @@ -0,0 +1,25 @@ + diff --git a/views/users/edit.handlebars b/views/users/edit.handlebars new file mode 100644 index 0000000..a60aa48 --- /dev/null +++ b/views/users/edit.handlebars @@ -0,0 +1,31 @@ + + +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
diff --git a/views/users/index.handlebars b/views/users/index.handlebars new file mode 100644 index 0000000..131589b --- /dev/null +++ b/views/users/index.handlebars @@ -0,0 +1,45 @@ + + +{{#if users.length }} + + + + + + + + + + + + + {{#each users as |user| }} + + + + + + + + + {{/each }} + +
First NameLast NameUsernameEmail
+ {{ user.fname }} + + {{ user.lname }} + + {{ user.username }} + + {{ user.email }} + + Edit + + Delete +
+{{else }} +

No users

+{{/if }} diff --git a/views/users/new.handlebars b/views/users/new.handlebars new file mode 100644 index 0000000..7f1a74d --- /dev/null +++ b/views/users/new.handlebars @@ -0,0 +1,29 @@ + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
diff --git a/views/users/show.handlebars b/views/users/show.handlebars new file mode 100644 index 0000000..42a3c4e --- /dev/null +++ b/views/users/show.handlebars @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyValue
First Name{{ user.fname }}
Last Name{{ user.lname }}
Username{{ user.username }}
Email{{ user.email }}