Loading opt/comments-server-side/app.js +17 −2 Original line number Diff line number Diff line Loading @@ -179,7 +179,7 @@ app.namespace('/auth/:sdk/:version', function(){ * `offset` and `limit` fields. I'd say it's a hack, but at least * it works for now. */ app.get('/comments_recent', function(req, res) { app.get('/comments_recent', util.getCommentReads, function(req, res) { var offset = parseInt(req.query.offset, 10) || 0; var limit = parseInt(req.query.limit, 10) || 100; var filter = { Loading @@ -187,6 +187,11 @@ app.namespace('/auth/:sdk/:version', function(){ sdk: req.params.sdk, version: req.params.version }; if (req.query.hideRead && req.commentMeta.reads.length > 0) { filter._id = { $nin: req.commentMeta.reads }; } Comment.find(filter).sort('createdAt', -1).skip(offset).limit(limit).run(function(err, comments) { comments = util.scoreComments(comments, req); // Count all comments, store count to last comment Loading Loading @@ -300,11 +305,21 @@ app.namespace('/auth/:sdk/:version', function(){ }); }); /** * Marks a comment 'read' */ app.post('/comments/:commentId/read', util.requireLoggedInUser, util.findCommentMeta, function(req, res) { req.commentMeta.metaType = 'read'; req.commentMeta.save(function(err, response) { res.send({ success: true }); }); }); /** * Get email subscriptions */ app.get('/subscriptions', util.getCommentSubscriptions, function(req, res) { res.json({ subscriptions: req.commentSubscriptions }); res.json({ subscriptions: req.commentMeta.subscriptions }); }); /** Loading opt/comments-server-side/database.js +10 −0 Original line number Diff line number Diff line Loading @@ -33,4 +33,14 @@ Subscription = mongoose.model('Subscription', new mongoose.Schema({ target: Array })); Meta = mongoose.model('Meta', new mongoose.Schema({ sdk: String, version: String, createdAt: Date, userId: Number, commentId: String, metaType: String })); mongoose.connect(config.mongoDb); opt/comments-server-side/util.js +64 −2 Original line number Diff line number Diff line Loading @@ -140,6 +140,32 @@ exports.findComment = function(req, res, next) { } }; /** * Looks up comment meta by comment ID. * * Stores it into `req.commentMeta`. * * @param {Object} req * @param {Object} res * @param {Function} next */ exports.findCommentMeta = function(req, res, next) { if (req.params.commentId) { var userCommentMeta = { userId: req.session.user.userid, commentId: req.params.commentId }; Meta.findOne(userCommentMeta, function(err, commentMeta) { req.commentMeta = commentMeta || new Meta(userCommentMeta); next(); }); } else { res.json({success: false, reason: 'No such comment'}); } }; /** * Ensures that user is allowed to modify/delete the comment, * that is, he is the owner of the comment or a moderator. Loading Loading @@ -288,7 +314,7 @@ exports.getCommentCounts = function(req, res, next) { * Retrieves list of commenting targets into which the current user * has subscribed for e-mail updates. * * Stores them into `req.commentSubscriptions` field as array: * Stores them into `req.commentMeta.subscriptions` field as array: * * [ * ["class", "Ext", ""], Loading @@ -301,13 +327,16 @@ exports.getCommentCounts = function(req, res, next) { * @param {Function} next */ exports.getCommentSubscriptions = function(req, res, next) { req.commentMeta = req.commentMeta || {}; if (req.session.user) { Subscription.find({ sdk: req.params.sdk, version: req.params.version, userId: req.session.user.userid }, function(err, subscriptions) { req.commentSubscriptions = _.map(subscriptions, function(subscription) { req.commentMeta.subscriptions = _.map(subscriptions, function(subscription) { return subscription.target; }); next(); Loading @@ -317,4 +346,37 @@ exports.getCommentSubscriptions = function(req, res, next) { } }; /** * Retrieves list of comments marked 'read' by the current user. * * Stores them into `req.commentMeta.reads` field as array: * * [ * 'abc123', * 'abc456', * 'abc789' * ] * * @param {Object} req * @param {Object} res * @param {Function} next */ exports.getCommentReads = function(req, res, next) { req.commentMeta = req.commentMeta || {}; if (req.session.user) { Meta.find({ userId: req.session.user.userid }, function(err, commentMeta) { req.commentMeta.reads = _.map(commentMeta, function(commentMeta) { return commentMeta.commentId; }); next(); }); } else { next(); } }; template/app/controller/Comments.js +40 −4 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ Ext.define('Docs.controller.Comments', { [ '.deleteComment', 'click', this.deleteComment], [ '.undoDeleteComment', 'click', this.undoDeleteComment], [ '.editComment', 'click', this.editComment], [ '.readComment', 'click', this.readComment], [ '.fetchMoreComments', 'click', this.fetchMoreComments], [ '.voteCommentUp', 'click', this.voteUp], [ '.voteCommentDown', 'click', this.voteDown] Loading Loading @@ -274,13 +275,20 @@ Ext.define('Docs.controller.Comments', { * Fetches the most recent comments */ fetchRecentComments: function(id, offset) { var params = { offset: offset || 0, limit: 100 } var hideRead = Ext.get('hideRead'); if (true || hideRead.checked) { params.hideRead = 1; } this.request("jsonp", { url: '/comments_recent', method: 'GET', params: { offset: offset || 0, limit: 100 }, params: params, success: function(response) { this.renderComments(response, id, { hideCommentForm: true, Loading Loading @@ -328,6 +336,34 @@ Ext.define('Docs.controller.Comments', { }); }, /** * Sends a read comment request to the server. */ readComment: function(cmp, el) { if (!this.isLoggedIn()) { return; } var id = Ext.get(el).up('.comment').getAttribute('id'), commentsEl = Ext.get(el).up('.comments-div'), target = commentsEl && commentsEl.getAttribute('id'); this.request("ajax", { url: '/comments/' + id + '/read', method: 'POST', callback: function(options, success, response) { var data = Ext.JSON.decode(response.responseText); if (data.success) { Ext.get(el).addCls('read'); } else { Ext.Msg.alert('Error', data.reason || "There was an error submitting your request"); } }, scope: this }); }, /** * Sends an undo request to the server. */ Loading template/app/view/Comments.js +1 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ Ext.define('Docs.view.Comments', { '<span class="problem">problem</span>', '</tpl>', '</div>', '<tpl if="showCls"><a href="#" class="readComment">Read</a></tpl>', '<tpl if="this.isMod() || this.isAuthor(values.author)"><a href="#" class="editComment">Edit</a><a href="#" class="deleteComment">Delete</a></tpl>', '<div class="time" title="{[this.date(values.createdAt)]}">{[this.dateStr(values.createdAt)]}</div>', '<div class="vote">', Loading Loading
opt/comments-server-side/app.js +17 −2 Original line number Diff line number Diff line Loading @@ -179,7 +179,7 @@ app.namespace('/auth/:sdk/:version', function(){ * `offset` and `limit` fields. I'd say it's a hack, but at least * it works for now. */ app.get('/comments_recent', function(req, res) { app.get('/comments_recent', util.getCommentReads, function(req, res) { var offset = parseInt(req.query.offset, 10) || 0; var limit = parseInt(req.query.limit, 10) || 100; var filter = { Loading @@ -187,6 +187,11 @@ app.namespace('/auth/:sdk/:version', function(){ sdk: req.params.sdk, version: req.params.version }; if (req.query.hideRead && req.commentMeta.reads.length > 0) { filter._id = { $nin: req.commentMeta.reads }; } Comment.find(filter).sort('createdAt', -1).skip(offset).limit(limit).run(function(err, comments) { comments = util.scoreComments(comments, req); // Count all comments, store count to last comment Loading Loading @@ -300,11 +305,21 @@ app.namespace('/auth/:sdk/:version', function(){ }); }); /** * Marks a comment 'read' */ app.post('/comments/:commentId/read', util.requireLoggedInUser, util.findCommentMeta, function(req, res) { req.commentMeta.metaType = 'read'; req.commentMeta.save(function(err, response) { res.send({ success: true }); }); }); /** * Get email subscriptions */ app.get('/subscriptions', util.getCommentSubscriptions, function(req, res) { res.json({ subscriptions: req.commentSubscriptions }); res.json({ subscriptions: req.commentMeta.subscriptions }); }); /** Loading
opt/comments-server-side/database.js +10 −0 Original line number Diff line number Diff line Loading @@ -33,4 +33,14 @@ Subscription = mongoose.model('Subscription', new mongoose.Schema({ target: Array })); Meta = mongoose.model('Meta', new mongoose.Schema({ sdk: String, version: String, createdAt: Date, userId: Number, commentId: String, metaType: String })); mongoose.connect(config.mongoDb);
opt/comments-server-side/util.js +64 −2 Original line number Diff line number Diff line Loading @@ -140,6 +140,32 @@ exports.findComment = function(req, res, next) { } }; /** * Looks up comment meta by comment ID. * * Stores it into `req.commentMeta`. * * @param {Object} req * @param {Object} res * @param {Function} next */ exports.findCommentMeta = function(req, res, next) { if (req.params.commentId) { var userCommentMeta = { userId: req.session.user.userid, commentId: req.params.commentId }; Meta.findOne(userCommentMeta, function(err, commentMeta) { req.commentMeta = commentMeta || new Meta(userCommentMeta); next(); }); } else { res.json({success: false, reason: 'No such comment'}); } }; /** * Ensures that user is allowed to modify/delete the comment, * that is, he is the owner of the comment or a moderator. Loading Loading @@ -288,7 +314,7 @@ exports.getCommentCounts = function(req, res, next) { * Retrieves list of commenting targets into which the current user * has subscribed for e-mail updates. * * Stores them into `req.commentSubscriptions` field as array: * Stores them into `req.commentMeta.subscriptions` field as array: * * [ * ["class", "Ext", ""], Loading @@ -301,13 +327,16 @@ exports.getCommentCounts = function(req, res, next) { * @param {Function} next */ exports.getCommentSubscriptions = function(req, res, next) { req.commentMeta = req.commentMeta || {}; if (req.session.user) { Subscription.find({ sdk: req.params.sdk, version: req.params.version, userId: req.session.user.userid }, function(err, subscriptions) { req.commentSubscriptions = _.map(subscriptions, function(subscription) { req.commentMeta.subscriptions = _.map(subscriptions, function(subscription) { return subscription.target; }); next(); Loading @@ -317,4 +346,37 @@ exports.getCommentSubscriptions = function(req, res, next) { } }; /** * Retrieves list of comments marked 'read' by the current user. * * Stores them into `req.commentMeta.reads` field as array: * * [ * 'abc123', * 'abc456', * 'abc789' * ] * * @param {Object} req * @param {Object} res * @param {Function} next */ exports.getCommentReads = function(req, res, next) { req.commentMeta = req.commentMeta || {}; if (req.session.user) { Meta.find({ userId: req.session.user.userid }, function(err, commentMeta) { req.commentMeta.reads = _.map(commentMeta, function(commentMeta) { return commentMeta.commentId; }); next(); }); } else { next(); } };
template/app/controller/Comments.js +40 −4 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ Ext.define('Docs.controller.Comments', { [ '.deleteComment', 'click', this.deleteComment], [ '.undoDeleteComment', 'click', this.undoDeleteComment], [ '.editComment', 'click', this.editComment], [ '.readComment', 'click', this.readComment], [ '.fetchMoreComments', 'click', this.fetchMoreComments], [ '.voteCommentUp', 'click', this.voteUp], [ '.voteCommentDown', 'click', this.voteDown] Loading Loading @@ -274,13 +275,20 @@ Ext.define('Docs.controller.Comments', { * Fetches the most recent comments */ fetchRecentComments: function(id, offset) { var params = { offset: offset || 0, limit: 100 } var hideRead = Ext.get('hideRead'); if (true || hideRead.checked) { params.hideRead = 1; } this.request("jsonp", { url: '/comments_recent', method: 'GET', params: { offset: offset || 0, limit: 100 }, params: params, success: function(response) { this.renderComments(response, id, { hideCommentForm: true, Loading Loading @@ -328,6 +336,34 @@ Ext.define('Docs.controller.Comments', { }); }, /** * Sends a read comment request to the server. */ readComment: function(cmp, el) { if (!this.isLoggedIn()) { return; } var id = Ext.get(el).up('.comment').getAttribute('id'), commentsEl = Ext.get(el).up('.comments-div'), target = commentsEl && commentsEl.getAttribute('id'); this.request("ajax", { url: '/comments/' + id + '/read', method: 'POST', callback: function(options, success, response) { var data = Ext.JSON.decode(response.responseText); if (data.success) { Ext.get(el).addCls('read'); } else { Ext.Msg.alert('Error', data.reason || "There was an error submitting your request"); } }, scope: this }); }, /** * Sends an undo request to the server. */ Loading
template/app/view/Comments.js +1 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ Ext.define('Docs.view.Comments', { '<span class="problem">problem</span>', '</tpl>', '</div>', '<tpl if="showCls"><a href="#" class="readComment">Read</a></tpl>', '<tpl if="this.isMod() || this.isAuthor(values.author)"><a href="#" class="editComment">Edit</a><a href="#" class="deleteComment">Delete</a></tpl>', '<div class="time" title="{[this.date(values.createdAt)]}">{[this.dateStr(values.createdAt)]}</div>', '<div class="vote">', Loading