Skip to content
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

Feature/questions 3/4 #3

Merged
merged 3 commits into from Apr 29, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions question3/README.md
@@ -0,0 +1,24 @@
# Question 3

In this problem you will update a document in the Enron dataset to illustrate your mastery of updating documents from the shell.

Please add the email address "mrpotatohead@mongodb.com" to the list of addresses in the "headers.To" array for the document with "headers.Message-ID" of "<8147308.1075851042335.JavaMail.evans@thyme>"

After you have completed that task, please download final3.zip from the Download Handout link and run final3-validate.js to get the validation code and put it in the box below without any extra spaces. The validation script assumes that it is connecting to a simple mongo instance on the standard port on localhost.

### Answer

Query
````
db.messages.update(
{
'headers.Message-ID': '<8147308.1075851042335.JavaMail.evans@thyme>'
},
{
$push: {
'headers.To': 'mrpotatohead@mongodb.com'
}
}
)
````

42 changes: 42 additions & 0 deletions question4/README.md
@@ -0,0 +1,42 @@
# Question 4

Enhancing the Blog to support viewers liking certain comments
In this problem, you will be enhancing the blog project to support users liking certain comments and the like counts showing up the in the permalink page.

Start by downloading Final4.zip and posts.json from the Download Handout link and loading up the blog dataset posts.json. The user interface has already been implemented for you. It's not fancy. The /post URL shows the like counts next to each comment and displays a Like button that you can click on. That Like button POSTS to the /like URL on the blog, makes the necessary changes to the database state (you are implementing this), and then redirects the browser back to the permalink page.

This full round trip and redisplay of the entire web page is not how you would implement liking in a modern web app, but it makes it easier for us to reason about, so we will go with it.

Your job is to search the code for the string "TODO: Final exam question - Increment the number of likes" and make any necessary changes. You can choose whatever schema you want, but you should note that the entry_template makes some assumptions about the how the like value will be encoded and if you go with a different convention than it assumes, you will need to make some adjustments.

The validation script does not look at the database. It looks at the blog.

The validation script, final4-validate.js, will fetch your blog, go to the first post's permalink page and attempt to increment the vote count. You run it as follows:

````
node final4-validate.js
````

Remember that the blog needs to be running as well as Mongo. The validation script takes some options if you want to run outside of localhost.

### Answer

Valid Code
````
this.incrementLikes = function(permalink, comment_ordinal, callback) {
"use strict";

var likes = {};
likes['comments.' + comment_ordinal + '.num_likes'] = 1;
console.log(likes);

posts.update({ 'permalink': permalink }, { $inc: likes }, function(err, post) {
"use strict";

if (err) return callback(Error("incrementLikes NYI"), null);;

callback(err, post);
});
}
````

14 changes: 14 additions & 0 deletions question4/blog/README.md
@@ -0,0 +1,14 @@
Blog project for M101JS

./app.js - entry point
./package.json - npm package description
./routes/ - Application routes
./posts.js - Posts Data Access Helper
./sessions.js - Sessions Data Access Helper
./users.js - Users Data Access Helper
./views/ - html templates

Getting started

npm install
node app.js
27 changes: 27 additions & 0 deletions question4/blog/app.js
@@ -0,0 +1,27 @@
var express = require('express')
, app = express() // Web framework to handle routing requests
, cons = require('consolidate') // Templating library adapter for Express
, MongoClient = require('mongodb').MongoClient // Driver for connecting to MongoDB
, routes = require('./routes'); // Routes for our application

MongoClient.connect('mongodb://localhost:27017/blog', function(err, db) {
"use strict";
if(err) throw err;

// Register our templating engine
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');

// Express middleware to populate 'req.cookies' so we can access cookies
app.use(express.cookieParser());

// Express middleware to populate 'req.body' so we can access POST variables
app.use(express.bodyParser());

// Application routes
routes(app, db);

app.listen(3000);
console.log('Express server listening on port 3000');
});
22 changes: 22 additions & 0 deletions question4/blog/package.json
@@ -0,0 +1,22 @@
{
"name": "blog",
"version": "0.0.0",
"description": "Blog Project for M101JS",
"main": "app.js",
"dependencies": {
"bcrypt-nodejs": "~0.0.3",
"consolidate": "~0.9.1",
"express": "~3.5",
"mongodb": "~1.4.34",
"swig": "~0.14.0",
"validator": "~1.1.3"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": "",
"author": "Shaun Verch <shaun.verch@10gen.com>",
"license": "BSD",
"private": true
}
131 changes: 131 additions & 0 deletions question4/blog/posts.js
@@ -0,0 +1,131 @@
/* The PostsDAO must be constructed with a connected database object */
function PostsDAO(db) {
"use strict";

/* If this constructor is called without the "new" operator, "this" points
* to the global object. Log a warning and call it correctly. */
if (false === (this instanceof PostsDAO)) {
console.log('Warning: PostsDAO constructor called without "new" operator');
return new PostsDAO(db);
}

var posts = db.collection("posts");

this.insertEntry = function (title, body, tags, author, callback) {
"use strict";
console.log("inserting blog entry" + title + body);

// fix up the permalink to not include whitespace
var permalink = title.replace( /\s/g, '_' );
permalink = permalink.replace( /\W/g, '' );

// Build a new post
var post = {"title": title,
"author": author,
"body": body,
"permalink":permalink,
"tags": tags,
"comments": [],
"date": new Date()}

// now insert the post
posts.insert(post, function (err, result) {
"use strict";

if (err) return callback(err, null);

console.log("Inserted new post");
callback(err, permalink);
});
}

this.getPosts = function(num, callback) {
"use strict";

posts.find().sort('date', -1).limit(num).toArray(function(err, items) {
"use strict";

if (err) return callback(err, null);

console.log("Found " + items.length + " posts");

callback(err, items);
});
}

this.getPostsByTag = function(tag, num, callback) {
"use strict";

posts.find({ tags : tag }).sort('date', -1).limit(num).toArray(function(err, items) {
"use strict";

if (err) return callback(err, null);

console.log("Found " + items.length + " posts");

callback(err, items);
});
}

this.getPostByPermalink = function(permalink, callback) {
"use strict";
posts.findOne({'permalink': permalink}, function(err, post) {
"use strict";

if (err) return callback(err, null);

// XXX: Look here for final exam to see where we store "num_likes"

// fix up likes values. set to zero if data is not present
if (typeof post.comments === 'undefined') {
post.comments = [];
}

// Each comment document in a post should have a "num_likes" entry, so we have to
// iterate all the comments in the post to make sure that is the case
for (var i = 0; i < post.comments.length; i++) {
if (typeof post.comments[i].num_likes === 'undefined') {
post.comments[i].num_likes = 0;
}
post.comments[i].comment_ordinal = i;
}
callback(err, post);
});
}

this.addComment = function(permalink, name, email, body, callback) {
"use strict";

var comment = {'author': name, 'body': body}

if (email != "") {
comment['email'] = email
}

posts.update({'permalink': permalink}, {'$push': {'comments': comment}}, function(err, numModified) {
"use strict";

if (err) return callback(err, null);

callback(err, numModified);
});
}

this.incrementLikes = function(permalink, comment_ordinal, callback) {
"use strict";

var likes = {};
likes['comments.' + comment_ordinal + '.num_likes'] = 1;
console.log(likes);

posts.update({ 'permalink': permalink }, { $inc: likes }, function(err, post) {
"use strict";

if (err) return callback(Error("incrementLikes NYI"), null);;

callback(err, post);
});
}
}

module.exports.PostsDAO = PostsDAO;