Comments.methods = {}; // ------------------------------------------------------------------------------------------- // // -------------------------------------- Submit Comment ------------------------------------- // // ------------------------------------------------------------------------------------------- // Comments.methods.new = function (comment) { var userId = comment.userId; // at this stage, a userId is expected // ------------------------------ Checks ------------------------------ // // Don't allow empty comments if (!comment.body) throw new Meteor.Error(704,i18n.t('your_comment_is_empty')); // ------------------------------ Properties ------------------------------ // var defaultProperties = { createdAt: new Date(), postedAt: new Date(), upvotes: 0, downvotes: 0, baseScore: 0, score: 0, author: Users.getDisplayNameById(userId) }; comment = _.extend(defaultProperties, comment); // ------------------------------ Callbacks ------------------------------ // // run all post submit server callbacks on comment object successively comment = Telescope.callbacks.run("commentSubmit", comment); // -------------------------------- Insert -------------------------------- // comment._id = Comments.insert(comment); // --------------------- Server-side Async Callbacks --------------------- // // run all post submit server callbacks on comment object successively // note: query for comment to get fresh document with collection-hooks effects applied Telescope.callbacks.runAsync("commentSubmitAsync", Comments.findOne(comment._id)); return comment; }; Comments.methods.edit = function (commentId, modifier, comment) { // ------------------------------ Callbacks ------------------------------ // modifier = Telescope.callbacks.run("commentEdit", modifier, comment); // ------------------------------ Update ------------------------------ // Comments.update(commentId, modifier); // ------------------------------ Callbacks ------------------------------ // Telescope.callbacks.runAsync("commentEditAsync", Comments.findOne(commentId), comment); // ------------------------------ After Update ------------------------------ // return Comments.findOne(commentId); }; // ------------------------------------------------------------------------------------------- // // ----------------------------------------- Methods ----------------------------------------- // // ------------------------------------------------------------------------------------------- // Meteor.methods({ 'comments.new': function(comment){ // checking might be redundant because SimpleSchema already enforces the schema, but you never know check(comment, Comments.simpleSchema()); // required properties: // postId // body // optional properties: // parentCommentId var user = Meteor.user(), hasAdminRights = Users.is.admin(user), schema = Comments.simpleSchema()._schema; // ------------------------------ Checks ------------------------------ // // check that user can comment if (!user || !Users.can.comment(user)) throw new Meteor.Error(i18n.t('you_need_to_login_or_be_invited_to_post_new_comments')); // ------------------------------ Rate Limiting ------------------------------ // if (!hasAdminRights) { var timeSinceLastComment = Users.timeSinceLast(user, Comments), commentInterval = Math.abs(parseInt(Telescope.settings.get('commentInterval',15))); // check that user waits more than 15 seconds between comments if((timeSinceLastComment < commentInterval)) throw new Meteor.Error(704, i18n.t('please_wait')+(commentInterval-timeSinceLastComment)+i18n.t('seconds_before_commenting_again')); } // ------------------------------ Properties ------------------------------ // // admin-only properties // userId // clear restricted properties _.keys(comment).forEach(function (fieldName) { // make an exception for postId, which should be setable but not modifiable if (fieldName === "postId") { // ok } else { var field = schema[fieldName]; if (!Users.can.submitField(user, field)) { throw new Meteor.Error("disallowed_property", i18n.t('disallowed_property_detected') + ": " + fieldName); } } }); // if no userId has been set, default to current user id if (!comment.userId) { comment.userId = user._id; } return Comments.methods.new(comment); }, 'comments.edit': function (modifier, commentId) { // checking might be redundant because SimpleSchema already enforces the schema, but you never know check(modifier, {$set: Comments.simpleSchema()}); check(commentId, String); var user = Meteor.user(), comment = Comments.findOne(commentId), schema = Comments.simpleSchema()._schema; // ------------------------------ Checks ------------------------------ // // check that user can edit if (!user || !Users.can.edit(user, comment)) { throw new Meteor.Error(601, i18n.t('sorry_you_cannot_edit_this_comment')); } // go over each field and throw an error if it's not editable // loop over each operation ($set, $unset, etc.) _.each(modifier, function (operation) { // loop over each property being operated on _.keys(operation).forEach(function (fieldName) { var field = schema[fieldName]; if (!Users.can.editField(user, field, comment)) { throw new Meteor.Error("disallowed_property", i18n.t('disallowed_property_detected') + ": " + fieldName); } }); }); Comments.methods.edit(commentId, modifier, comment); }, 'comments.deleteById': function (commentId) { check(commentId, String); var comment = Comments.findOne(commentId); var user = Meteor.user(); if(Users.can.edit(user, comment)){ // decrement post comment count and remove user ID from post Posts.update(comment.postId, { $inc: {commentCount: -1}, $pull: {commenters: comment.userId} }); // decrement user comment count and remove comment ID from user Meteor.users.update({_id: comment.userId}, { $inc: {'telescope.commentCount': -1} }); // note: should we also decrease user's comment karma ? // We don't actually delete the comment to avoid losing all child comments. // Instead, we give it a special flag Comments.update({_id: commentId}, {$set: { body: 'Deleted', htmlBody: 'Deleted', isDeleted: true }}); }else{ Messages.flash("You don't have permission to delete this comment.", "error"); } }, 'comments.upvote': function (commentId) { check(commentId, String); return Telescope.operateOnItem.call(this, Comments, commentId, Meteor.user(), "upvote"); }, 'comments.downvote': function (commentId) { check(commentId, String); return Telescope.operateOnItem.call(this, Comments, commentId, Meteor.user(), "downvote"); }, 'comments.cancelUpvote': function (commentId) { check(commentId, String); return Telescope.operateOnItem.call(this, Comments, commentId, Meteor.user(), "cancelUpvote"); }, 'comments.cancelDownvote': function (commentId) { check(commentId, String); return Telescope.operateOnItem.call(this, Comments, commentId, Meteor.user(), "cancelDownvote"); } });