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 @@
+ Original Message: {{ comment.body }}New Comment
+ Commenting on a {{ parentType }}
+
Posted At | +Title | +Body | +Username | ++ | + |
---|---|---|---|---|---|
+ {{ post.postedAt }} + | ++ {{ post.title }} + | ++ {{ post.body }} + | ++ {{ post.author.username }} + | + {{#if post.editable}} ++ Edit + | ++ Delete + | + {{/if}} +
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 @@ +{{ post.body }}
+ Comment +{{ comment.author.username }} said:
+{{ comment.body }}
+ + {{#each comment.children as |childcomment|}} +First Name | +Last Name | +Username | ++ | + | |
---|---|---|---|---|---|
+ {{ user.fname }} + | ++ {{ user.lname }} + | ++ {{ user.username }} + | ++ {{ user.email }} + | ++ Edit + | ++ Delete + | +
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 @@ +Key | +Value | +
---|---|
First Name | +{{ user.fname }} | +
Last Name | +{{ user.lname }} | +
Username | +{{ user.username }} | +
{{ user.email }} | +