Loading comments/api_adapter.js +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ module.exports = { contentHtml: comment.content_html, createdAt: String(comment.created_at), score: comment.vote, upVote: comment.vote_dir === 1, downVote: comment.vote_dir === -1, moderator: comment.moderator, emailHash: crypto.createHash('md5').update(comment.email).digest("hex") }; Loading comments/app.js +3 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,9 @@ app.get('/auth/:sdk/:version/comments', services.comments, function(req, res) { } var target = ApiAdapter.targetFromJson(JSON.parse(req.query.startkey)); if (req.session.user) { req.comments.showVoteDirBy(req.session.user.id); } req.comments.find(target, function(err, comments) { res.json(comments.map(ApiAdapter.commentToJson)); }); Loading comments/comments.js +42 −8 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ function Comments(db, domain) { this.db = db; this.domain = domain; this.targets = new Targets(db, domain); this.view = "full_visible_comments"; this.view = "full_visible_comments AS comments"; this.fields = "*"; } Comments.prototype = { Loading @@ -29,7 +30,19 @@ Comments.prototype = { * @param {Boolean} show */ showDeleted: function(show) { this.view = show ? "full_comments" : "full_visible_comments"; this.view = show ? "full_comments AS comments" : "full_visible_comments as comments"; }, /** * Includes a `vote_dir` field into the comment records returned * by #get* and #find* methods. The `vote_dir` field will be 1 * when the user has upvoted the comment, -1 if he has downvoted * it or null if he has not voted on the comment. * @param {Number} user_id The ID of the user who's votes to inspect. */ showVoteDirBy: function(user_id) { var sql = "*, (SELECT SUM(value) FROM votes WHERE user_id = ? AND comment_id = comments.id) AS vote_dir"; this.fields = this.db.format(sql, [user_id]); }, /** Loading @@ -42,12 +55,14 @@ Comments.prototype = { */ getById: function(id, callback) { var sql = [ 'SELECT *', 'SELECT ', this.fields, 'FROM', this.view, 'WHERE domain = ? AND id = ?' ]; this.db.queryOne(sql, [this.domain, id], callback); this.db.query(sql, [this.domain, id], this.fixVoteDir(function(err, rows) { callback(err, rows && rows[0]); })); }, /** Loading @@ -64,13 +79,13 @@ Comments.prototype = { */ find: function(target, callback) { var sql = [ 'SELECT *', 'SELECT ', this.fields, 'FROM', this.view, 'WHERE domain = ? AND type = ? AND cls = ? AND member = ?', 'ORDER BY created_at' ]; this.db.query(sql, [this.domain, target.type, target.cls, target.member], callback); this.db.query(sql, [this.domain, target.type, target.cls, target.member], this.fixVoteDir(callback)); }, /** Loading @@ -86,14 +101,14 @@ Comments.prototype = { */ findRecent: function(opts, callback) { var sql = [ 'SELECT *', 'SELECT ', this.fields, 'FROM', this.view, 'WHERE domain = ?', 'ORDER BY created_at DESC', 'LIMIT ? OFFSET ?' ]; this.db.query(sql, [this.domain, opts.limit||100, opts.offset||0], callback); this.db.query(sql, [this.domain, opts.limit||100, opts.offset||0], this.fixVoteDir(callback)); }, /** Loading Loading @@ -292,6 +307,25 @@ Comments.prototype = { callback(null, vote.value); } }.bind(this)); }, // Helper that converts all vote_dir fields into numbers. For some // reason the vote_dir field is a string by default, but we don't // want that. fixVoteDir: function(callback) { return function(err, rows) { if (err) { callback(err); return; } callback(null, rows.map(function(r) { if (r.vote_dir) { r.vote_dir = +r.vote_dir; } return r; })); }; } }; Loading comments/comments.spec.js +24 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,30 @@ describe("Comments", function() { }); }); describe("after calling showVoteDirBy(author)", function() { beforeEach(function() { comments.showVoteDirBy(2); }); it("includes the upvote by that author", function(done) { comments.getById(1, function(err, com) { expect(com.vote_dir).toEqual(1); done(); }); }); it("includes the downvote by that author", function(done) { comments.getById(15, function(err, com) { expect(com.vote_dir).toEqual(-1); done(); }); }); it("includes no vote if user hasn't voted on a comment", function(done) { comments.getById(7, function(err, com) { expect(com.vote_dir).toEqual(null); done(); }); }); }); it("#find returns all undeleted comments for a target", function(done) { comments.find({type: "class", cls: "Ext", member: ""}, function(err, rows) { expect(rows.length).toEqual(5); Loading comments/db_facade.js +11 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,17 @@ DbFacade.prototype = { this.connection.end(); }, /** * Replaces ? placeholders in SQL string. * * @param {String} sql * @param {Array} params * @return {String} */ format: function(sql, params) { return this.connection.format(sql, params); }, removeField: function(obj, fieldName) { var newObj = {}; for (var i in obj) { Loading Loading
comments/api_adapter.js +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ module.exports = { contentHtml: comment.content_html, createdAt: String(comment.created_at), score: comment.vote, upVote: comment.vote_dir === 1, downVote: comment.vote_dir === -1, moderator: comment.moderator, emailHash: crypto.createHash('md5').update(comment.email).digest("hex") }; Loading
comments/app.js +3 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,9 @@ app.get('/auth/:sdk/:version/comments', services.comments, function(req, res) { } var target = ApiAdapter.targetFromJson(JSON.parse(req.query.startkey)); if (req.session.user) { req.comments.showVoteDirBy(req.session.user.id); } req.comments.find(target, function(err, comments) { res.json(comments.map(ApiAdapter.commentToJson)); }); Loading
comments/comments.js +42 −8 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ function Comments(db, domain) { this.db = db; this.domain = domain; this.targets = new Targets(db, domain); this.view = "full_visible_comments"; this.view = "full_visible_comments AS comments"; this.fields = "*"; } Comments.prototype = { Loading @@ -29,7 +30,19 @@ Comments.prototype = { * @param {Boolean} show */ showDeleted: function(show) { this.view = show ? "full_comments" : "full_visible_comments"; this.view = show ? "full_comments AS comments" : "full_visible_comments as comments"; }, /** * Includes a `vote_dir` field into the comment records returned * by #get* and #find* methods. The `vote_dir` field will be 1 * when the user has upvoted the comment, -1 if he has downvoted * it or null if he has not voted on the comment. * @param {Number} user_id The ID of the user who's votes to inspect. */ showVoteDirBy: function(user_id) { var sql = "*, (SELECT SUM(value) FROM votes WHERE user_id = ? AND comment_id = comments.id) AS vote_dir"; this.fields = this.db.format(sql, [user_id]); }, /** Loading @@ -42,12 +55,14 @@ Comments.prototype = { */ getById: function(id, callback) { var sql = [ 'SELECT *', 'SELECT ', this.fields, 'FROM', this.view, 'WHERE domain = ? AND id = ?' ]; this.db.queryOne(sql, [this.domain, id], callback); this.db.query(sql, [this.domain, id], this.fixVoteDir(function(err, rows) { callback(err, rows && rows[0]); })); }, /** Loading @@ -64,13 +79,13 @@ Comments.prototype = { */ find: function(target, callback) { var sql = [ 'SELECT *', 'SELECT ', this.fields, 'FROM', this.view, 'WHERE domain = ? AND type = ? AND cls = ? AND member = ?', 'ORDER BY created_at' ]; this.db.query(sql, [this.domain, target.type, target.cls, target.member], callback); this.db.query(sql, [this.domain, target.type, target.cls, target.member], this.fixVoteDir(callback)); }, /** Loading @@ -86,14 +101,14 @@ Comments.prototype = { */ findRecent: function(opts, callback) { var sql = [ 'SELECT *', 'SELECT ', this.fields, 'FROM', this.view, 'WHERE domain = ?', 'ORDER BY created_at DESC', 'LIMIT ? OFFSET ?' ]; this.db.query(sql, [this.domain, opts.limit||100, opts.offset||0], callback); this.db.query(sql, [this.domain, opts.limit||100, opts.offset||0], this.fixVoteDir(callback)); }, /** Loading Loading @@ -292,6 +307,25 @@ Comments.prototype = { callback(null, vote.value); } }.bind(this)); }, // Helper that converts all vote_dir fields into numbers. For some // reason the vote_dir field is a string by default, but we don't // want that. fixVoteDir: function(callback) { return function(err, rows) { if (err) { callback(err); return; } callback(null, rows.map(function(r) { if (r.vote_dir) { r.vote_dir = +r.vote_dir; } return r; })); }; } }; Loading
comments/comments.spec.js +24 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,30 @@ describe("Comments", function() { }); }); describe("after calling showVoteDirBy(author)", function() { beforeEach(function() { comments.showVoteDirBy(2); }); it("includes the upvote by that author", function(done) { comments.getById(1, function(err, com) { expect(com.vote_dir).toEqual(1); done(); }); }); it("includes the downvote by that author", function(done) { comments.getById(15, function(err, com) { expect(com.vote_dir).toEqual(-1); done(); }); }); it("includes no vote if user hasn't voted on a comment", function(done) { comments.getById(7, function(err, com) { expect(com.vote_dir).toEqual(null); done(); }); }); }); it("#find returns all undeleted comments for a target", function(done) { comments.find({type: "class", cls: "Ext", member: ""}, function(err, rows) { expect(rows.length).toEqual(5); Loading
comments/db_facade.js +11 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,17 @@ DbFacade.prototype = { this.connection.end(); }, /** * Replaces ? placeholders in SQL string. * * @param {String} sql * @param {Array} params * @return {String} */ format: function(sql, params) { return this.connection.format(sql, params); }, removeField: function(obj, fieldName) { var newObj = {}; for (var i in obj) { Loading