// 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 }); var postId = Posts.insert(post); return { _id: postId }; } });