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) {
    return (_.without(fieldNames, 'url', 'title').length > 0);
  },

  update: function(userId, post, fieldName, modifier) {
    var errors = validatePost(modifier.$set);
    return errors.title || errors.url;
  }
});

Meteor.methods({
  postInsert: function(postAttributes) {
    check(Meteor.userId(), String);
    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 to your post');
    }

    var postWithSameLink = Posts.findOne({ url: postAttributes.url });

    if (postWithSameLink) {
      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
    };
  },

  postUpdate: function(postAttributes) {
    check(Meteor.userId(), String);
    check(postAttributes, {
      title: String,
      url: String,
      _id: String
    });

    var postWithSameLink = Posts.findOne({ url: postAttributes.url });

    if (postWithSameLink) {
      return {
        postExists: true,
        _id: postWithSameLink._id
      };
    }

    var postId = Post.update(postAttributes._id, {$set: postProperties});

  }
});

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;
}

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) {
    return (_.without(fieldNames, 'url', 'title').length > 0);
  },

  update: function(userId, post, fieldName, modifier) {
    var errors = validatePost(modifier.$set);
    return errors.title || errors.url;
  }
});

Meteor.methods({
  postInsert: function(postAttributes) {
    check(Meteor.userId(), String);
    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 to your post');
    }

    var postWithSameLink = Posts.findOne({ url: postAttributes.url });

    if (postWithSameLink) {
      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
    };
  },

  postUpdate: function(postAttributes) {
    check(Meteor.userId(), String);
    check(postAttributes, {
      title: String,
      url: String,
      _id: String
    });

    var postWithSameLink = Posts.findOne({ url: postAttributes.url });

    if (postWithSameLink) {
      return {
        postExists: true,
        _id: postWithSameLink._id
      };
    }

    var postId = Post.update(postAttributes._id, {$set: postProperties});

  },

  upvote: function(postId) {
    check(this.userId, String);
    check(postId, String);

    var post = Posts.findOne(postId);

    if (!post) {
      throw new Meteor.Error('invalid', 'Post not found');
    }
    if (_.include(post.upvoters, this.userId)) {
      throw new Meteor.Error('invalid', 'Already upvoted this post');
    }
    
    Posts.update(post._id, {
      $addToSet: { upvoters: this.userId },
      $inc: { votes: 1 }
    });
  }
});

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;
}

Add upvote method