0

I'm following the MeteorJS example for a leaderboard here: https://www.meteor.com/examples/leaderboard

I want to limit the votes to once per day (per IP address). What's the best way to do this?

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
user3822146
  • 114
  • 3
  • 10
  • 1
    Create a Meteor method for upvotes. In the Method you can access the ip of the voter by this.connection.clientAddresshttp://docs.meteor.com/#method_connection – imslavko Jul 18 '14 at 03:14
  • @imslavko Can you please give me some source code? Thanks. – user3822146 Jul 18 '14 at 03:28

1 Answers1

2

The following solution assumes you are starting with a clean version of the leaderboard example.

Step one: Declare a new collection to hold IP address and date information. This can be added just below the definition of Players.

IPs = new Meteor.Collection('ips');

Step two: Replace the increment event with a call to our new method givePoints.

Template.leaderboard.events({
  'click input.inc': function() {
    var playerId = Session.get('selected_player');
    Meteor.call('givePoints', playerId, function(err) {
      if (err)
        alert(err.reason);
    });
  }
});

Step three: Define the givePoints method on the server (this.connection only works on the server). You can do this by inserting the following anywhere inside of the Meteor.isServer check or by creating a new file under the /server directory.

Meteor.methods({
  givePoints: function(playerId) {
    check(playerId, String);

    // we want to use a date with a 1-day granularity
    var startOfDay = new Date;
    startOfDay.setHours(0, 0, 0, 0);

    // the IP address of the caller
    ip = this.connection.clientAddress;

    // check by ip and date (these should be indexed)
    if (IPs.findOne({ip: ip, date: startOfDay})) {
      throw new Meteor.Error(403, 'You already voted!');
    } else {
      // the player has not voted yet
      Players.update(playerId, {$inc: {score: 5}});

      // make sure she cannot vote again today
      IPs.insert({ip: ip, date: startOfDay});
    }
  }
});

The complete code can be seen in this gist.

David Weldon
  • 63,632
  • 11
  • 148
  • 146
  • Everything looks good, but for some reason it's not working. Am I supposed to put step three in the `Meteor.isServer` function? I'm getting no errors. I've tried putting in before, in, and after that function. Do you have any suggestions? – user3822146 Jul 21 '14 at 01:16
  • 1
    Yeah you want to put it under the `Meteor.isServer` check, or put it in a new file anywhere in the `/server` directory. I modified the answer to be more clear. I can create a gist if this still isn't working for you. – David Weldon Jul 21 '14 at 02:10
  • Would you mind creating a gist? Don't understand why it's not working. Thanks so much. – user3822146 Jul 21 '14 at 03:16
  • 1
    Okay I added the gist at the end of the answer. So if you check out a clean leaderboard project and replace `leaderboard.js` with the above, it should work. When running locally the expected experience would be that you can vote for one person, and then not again until the next day (there isn't any visual feedback apart from the 2nd vote not changing the score). – David Weldon Jul 21 '14 at 03:48
  • Is there a way to display an error message? Can I just change out the 403 message with `console.log("ERROR")`? – user3822146 Jul 21 '14 at 19:12
  • 1
    Sure - I updated the code with an example. It the method received an error from the server it will alert the user. – David Weldon Jul 21 '14 at 19:57