// Not a "var", to make it global. Posts = new Mongo.Collection('posts'); Posts.allow({ update: function (userId, post) { return ownsDocument(userId, post); }, remove: function (userId, post) { return ownsDocument(userId, post); } }); Posts.deny({ update: function (userId, post, fieldNames) { // _.without() is like PHP array_diff($source, ...$keys). // May only edit the following two fields: return (_.without(fieldNames, "url", "title").length > 0); } }); Posts.deny({ // In a post edit, the update is performed by a $set modifier, with the same // fields as the base inserted post: url and title, so we can pass it to // the post validator as it currently stands. update: function (userId, post, fieldNames, modifier) { var errors = validatePost(modifier.$set); return errors.title || errors.url; } }); validatePost = function (post) { var errors = {}; if (!post.title) { errors.title = "Please fill in a headline"; } if (!post.url) { errors.url = "Please fill in a URL"; } return errors; }; // This is in lib/ instead of server/ for latency compensation. Meteor.methods({ postInsert: function(postAttributes) { "use strict"; check(this.userId, String); // Or Meteor.userId() ? check(postAttributes, { title: String, url: String }); var errors = validatePost(postAttributes); if (errors.title || errors.url) { throw new Meteor.Error('invalid-post', "You must set a title and URL for your post"); } var postWithSameLink = Posts.findOne({ url: postAttributes.url }); if (postWithSameLink) { // Return to skip the insert. return { postExists: true, _id: postWithSameLink._id }; } var user = Meteor.user(); var post = _.extend(postAttributes, { userId: user._id, author: user.username, submitted: new Date(), commentsCount: 0, upvoters: [], votes: 0 }); var postId = Posts.insert(post); return { _id: postId }; }, upvote: function (postId) { check(this.userId, Match.OneOf(null, String)); check(postId, String); if (this.userId === null) { throw new Meteor.Error('invalid', 'Not logged in'); } var affected = Posts.update({ _id: postId, upvoters: { $ne: this.userId } }, { $addToSet: { upvoters: this.userId }, $inc: { votes: 1 } }); if (!affected) { throw new Meteor.Error('invalid', "You weren't able to upvote that post"); } } });