Ralph David Abernathy
Ralph David Abernathy

Reputation: 5518

How to avoid duplicate users from being mentioned by bot within Slack?

So I'm working on a bot for Slack that mentions a random user every week. I get to a point where the bot does exactly that, but I'm not sure how to avoid duplicates. As you can see in the screenshot below, duplicate names are being shown:

duplicate names

Here is my code:

// Handle events related to the websocket connection to Slack
controller.on('rtm_open', function (bot) {
  console.log('** The RTM api just connected!');

  // Get all users
  bot.api.users.list({}, function(err, list){

    // If list and members exist
    if (list && list.members) {

      list.members = list.members.filter(function(member) {
        return (member.real_name != undefined && member.real_name != "" && member.real_name != null && member.real_name != "slackbot");
      });

      // console.log(list.members);
      var previousRandomNumber = -1;

      // Every X amount of milliseconds
      var interval = setInterval(function() {
        var members = list.members;

        // Generating random number from 0 to how many members exist (exclusive) in the member list
        var randomNumber = Math.floor(Math.random() * members.length);

        console.log('1) previous: ' + previousRandomNumber + '  randomNumber ' + randomNumber);
        if (previousRandomNumber == randomNumber) {
          randomNumber = Math.floor(Math.random() * members.length);
        }
        console.log('2) previous: ' + previousRandomNumber + '  randomNumber ' + randomNumber);

        previousRandomNumber = randomNumber;

        // Get random name
        var randomName = members[randomNumber].name;

        //console.log(randomName);

        // If random name is null or undefined, reshuffle.
        if (randomName == null || randomName == "" || randomName == undefined) {
          console.log('user has been deleted');

          // clearInterval(interval);

        } else {
          console.log('actual person - ' + randomName);
          // Configuring webhook and sending message to channel
          bot.configureIncomingWebhook({url: 'https://hooks.slack.com/services/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'});
          bot.sendWebhook({
            text: '@' + randomName + ", you've been selected for #snapshot! ",
            channel: '#test',
          },function(err,res) {
            // handle error
          });
        }
      }, 3000); // 604800000 ms = 1 week
      console.log("message");
    }
  })
});

Link to repo on GitHub

Does anyone know how I could somehow splice the names that have already been mentioned from the array?

Upvotes: 2

Views: 871

Answers (2)

Just a student
Just a student

Reputation: 11050

First, I agree with Erik that you need to explicitly ensure that you do not select the same member twice. This can be done by storing members you already selected (or still need to select) in a database. We don't have enough details to help you with how to do that.

What I want to add, however, is that the best way to select random members without repetition is not by randomly selecting a user and making sure you did not select that member before. That can take a long time. You can remove a member from the array, but there is another way.

Shuffle (in the right way!) the array of members and then simply loop over them in order. You can shuffle again when all members have been selected. Here is an example using ES6 syntax and a generator, because this seems an ideal use case for it. If the browser support (no IE, other major browsers are fine) is not a problem, you can use this by passing in your list.members to uniqueRandomIterate and use iterator.next().value in your interval.

function shuffle(a) {
  for (let i = a.length; i; i--) {
    let j = Math.floor(Math.random() * i);
    [a[i - 1], a[j]] = [a[j], a[i - 1]];
  }
}

function* uniqueRandomIterate(array) {
  var ind = 0;
  while (true) {
    shuffle(array);
    for (let i = 0; i < members.length; ++i) {
      yield array[i];
    }
    console.log('got everyone, starting over');
  }
}

var members = ['a', 'b', 'c', 'd', 'e', 'f'],
    iterator = uniqueRandomIterate(members);
for (let i = 0; i < 3 * members.length; ++i) {
  console.log(iterator.next().value);
}
.as-console-wrapper {
  max-height: 100% !important;
}

Upvotes: 3

Erik Kalkoken
Erik Kalkoken

Reputation: 32837

To avoid duplicated you will need to store the IDs of users that were already mentioned and remove those from your copy of the userlist each time you run it (e.g. once a week). Until all users have been mentioned, then you have to reset.

There are many ways how you can store the IDs. e.g. you can put them into a database or you can safe them into a JSON file stored on the server.

Upvotes: 4

Related Questions