Slack Bot (Tutorial 2019)

Slack Bot

Slack API to build bots

This blog explains how Java developers build a fully functional Slack bot that runs as a standalone application. And then how bot establishes a WebSocket connection using the Slack RTM API.

 

Simple Slack API internals

Here’s how all Slack bots made with the Simple Slack API work:

  1. The bot establishes a WebSocket connection using the Slack RTM API.
  2. Once it’s connected, the bot receives various information about the team such as users, channels, etc.
  3. Once all of this information has been received, the library keeps a web socket thread running that unmarshalls (deserializes) the Slack events into Java objects. When an event arrives, the library dispatches them to all registered listeners.
  4. A heartbeat function is included in the library and is set to automatically monitor the connection status by sending Slack ping requests at regular intervals.

 

Here’s an example of a JSON event sent over the WebSocket connection:

{
"type": "message",
"user": "U042PASSS",
"text": "Hello world",
"bot_id": "B023PAXME",
"user_team": "T055KFDH",
"team": "T055KFDH",
"user_profile": {
"avatar_hash": "03f50aa1ce70",
"image_72": "https:\/\/avatars.slack-edge.com\/2015-03-18\/4aze.jpg",
"first_name": "Rob", "real_name": "Rob Ot", "name": "rob_ot"
},
"channel": "D023PFEF",
"ts": "1465298109.000035"
}

 

A bot built from Simple Slack API can react to these events using a set of listeners, and by using the Slack Web API RPC methods to act on the channels: sending a message, creating a channel, pinning a reaction emoji, etc.

 

Simple to use

By handling the WebSocket connection, the JSON stream, and API mappings, the Simple Slack API lets you focus on the business logic you want to implement on top of Slack.

 

You shouldn’t have to bother about the connection status, or parsing JSON, or mastering the HTTP protocol. The core class of the API is SlackSession, which lets you register listeners or send commands just by calling methods.

 

Initiating a Slack session

The first thing you need to do is to instruct the Simple Slack API to connect to Slack by opening a session. Once opened, this session will be the entry point that you can use to interact programmatically with the Slack team. Here’s how to open a session:

SlackSession session = SlackSessionFactory.

createWebSocketSlackSession("bot-token-here");

session.connect();

 

That’s it. With these two lines of code, your bot is connected to a Slack team.

  1. Accessing the team’s users and channels
  2. Once the session is opened, you can access the team user directory or browse the public channel list from the newly created session.

Here’s how to retrieve a channel:

 searching by channel name
SlackChannel channel1 = session.findChannelByName("cool-channel");
// searching by channel id
SlackChannel channel2 = session.findChannelById("C0123456");
// Fetching all the channel list
Collection<SlackChannel> channels = session.getChannels();
And here’s how to retrieve a user:
// searching by user name
SlackUser user1 session.findUserByUserName("john.doe");
// searching by email
SlackUser user2 session.findUserByEmail("john.doe@acme.com");
// searching by user id
SlackUser user3 session.findUserById("U012345");
// Fetching all the user list
Collection<SlackUser> users = getUsers();
// Knowing the user the bot is using to connect to Slack
SlackPersona botId = session.sessionPersona();

 

Ids

In the code used in this hack, you can see some methods for retrieving users or channels if you know their ID. The ID is a unique internal identifier created and managed by Slack.

 

Interacting with the team

Now that you have an open session and you know how to get the team’s channels and users, you can interact with those objects. All of this method use the Slack Web API described. Virtually all of the Slack Web API methods are accessible through this library.

 

Here’s how to join a channel:

session.join channel("slack-hacks");
And how to post a message on a channel:
SlackChannel channel = session.findChannelById("C0123456"); session.sendMessage(channel, "Hello world");
And how to invite a user to a channel:
SlackChannel channel = session.findChannelById("C0123456"); SlackUser user = session.findUserByUserName("john.doe"); session.inviteToChannel(channel, user);

 

A bot connected to a Slack client

To get a better understanding of Simple Slack API, think of the Slack bot you are developing as being connected like a standard user using a Slack client.

 

The commands you are sending would behave in the same way if you were using the client feature. For example, joining a channel that doesn’t exist creates it, yet posting a message on a channel you have not joined will fail.

 

Listening to team events

You can make the bot aware of what is going on in the channel. There are dozens of different events to listen to, so let’s examine the most interesting ones and see how to easily react to these events.

 

Here’s how to make your bot listen to a posted message:

session.addMessagePostedListener(new SlackMessagePostedListener() { @Override
public void onEvent(SlackMessagePosted event, SlackSession session) {
// put code here that you want to execute on such event
}
});
And here’s how you make the bot listen with a lambda expression:
session.addMessagePostedListener((_event, _session) -> {
// put the code here that you want to execute on such event
});

 

Your listener will get all of the message events as its first parameter regardless of which channel the message was posted on or which user posted it. So, generally, the first thing the listener code will do is to filter out events based on the attributes of channels/users. Those attributes are available on the event object itself.

 

Listening to channel creation

The example below combines all the things you’ve seen so far to interact with the team and the channel-creation event listening mechanism. This code shows how to have your bot join each newly created channel:

session.addchannelCreatedListener((_event, _session) -> {
if (_event.getCreator().getId().equals(
_session.sessionPersona().getId())) {
_session.joinChannel(_event.getSlackChannel().getName());
}
});

 

Now that you have been introduced to the Simple Slack API, let’s put it to use in the next hack.

 

Build a JSON pretty-printer bot

In this hack, you’ll learn how to build your first Slack bot using the Simple Slack API library. This bot will prettify any JSON file that is sent to it. This is a convenient tool to have when you are developing tools around the JSON based protocol, like the Slack RTM API.

 

In this step-by-step example, we will assume you know how to code in Java and that you have JDK 8 already installed. We will use Gradle as our build tool to put everything together.

Setup

 

Before you can start building your bot, you need to do some setup:

1. Download the latest distribution of Gradle from http:// gradle.org/gradle-download/

2. Unzip the distribution into a directory of your choice

3. Create a GRADLE_HOME environment variable

4. Add GRADLE_HOME/bin to your PATH environment variable

 

After you’ve performed those setup steps, you should be able to run Gradle from the command line. Now that you have Gradle set up, you’re ready to perform the remaining setup steps:

1. Create a directory where you want to put your bot source files

2. Create a build. gradle file with the following content:

 

apply plugin: 'java' repositories {

mavenCentral()

}

dependencies {

compile 'com.ullink.slack:simpleslackapi:0.6.0' compile 'org.apache.httpcomponents:httpclient:4.4' compile 'com.cedarsoftware:json-io:4.4.0'

}
  • 1. Create the following directory: class='lazy' data-src/main/slack
  • 2. In this newly created directory, create the following file: JSON PrettyPrinter.java

+ build.gradle

+ If you are not familiar with Gradle, build.gradle is used to describe the project’s structure, its dependencies, and how to retrieve them. So in this hack, you will use the last version of simple slack API and json-io, an open source library, which provide a simple tool to prettify JSON. 

 

You are now ready to write the bot code. To keep things as simple as possible, everything in his hack will be written in the main method in a single class.

 

Bot skeleton

We have a clear vision of what the bot is supposed to do (prettify JSON files), so let’s try to define a skeleton. As you’ve seen, it’s quite easy to create a Slack session, add a listener, and connect to a Slack team. So, let’s create a skeleton for the bot:

public class JSONPrettyPrinter {
private static final String TOKEN = "insert_here_your_bot_token";
public static void main(String [] args) {
//create a session using the token
SlackSession session = SlackSessionFactory.createWebSocketSlackSession(TOKEN);
//add to the session a listener to get informed of all
//message posted that the bot could be aware of
session.addMessagePostedListener(JSONPrettyPrinter::processEvent);
//connect to the Slack team
session.connect();
//make the main thread wait and delegate the event processing
//to the session, dispatching them to the listener
Thread.sleep(Long.MAX_VALUE);
}
}

 

So far, there’s nothing new here except the call to the processEvent static method. Let’s have a closer look at what this method should do.

 

Processing the event

  1. When the bot receives a SlackMessagePosted event, the logic that handles the event is easy to implement
  2. Does the event need to be processed? If not, then don’t process it

If the event needs to be processed:

  1. download the file attached to the message
  2. format the JSON
  3.  send back a new file containing the formatted JSON

If an issue occurs during the processing (for example, the bot is unable to download the file, or the file doesn’t contain JSON formatted text) then notify the user of this fact.

 

In Java, this is expressed as follows:

private static void processEvent(SlackMessagePosted event,
SlackSession session) {
// does the event needs to be processed?
if (!isFileSentFromAnotherUser(event, session)) {
return;
}
//trying to pretty print the file
try {
sendBackPrettifiedFile(event, session, formatJson(downloadFile(event)));
} catch (Exception e) { failOnException(event, session, e);
}
}

 

Determining whether the event needs to be processed

The isFileSentFromAnotherUser method serves as a filter that discards every event the bot doesn’t have to process. Here are the events the bot should ignore:

  1. messages without a file attached to them
  2. messages sent on a non-direct channel
  3. messages sent by the bot itself

Here is the implementation of this using Java:

private static boolean isFileSentFromAnotherUser(SlackMessagePosted event,
SlackSession session) {
//if the event is not on a direct channel
if (!event.getChannel().isDirect())
return false;
//if the event was triggered by the bot
if (event.getSender().getId().equals( session.sessionPersona().getId()))
return false;
//if the event doesn't contain a file
if (event.getSlackFile() == null) return false;
//otherwise
return true;
}

 

Download the file attached to the download file

Whenever a file is referenced in a Slack event, the URL to download it is provided. For security reasons, this URL is not accessible to non-authorized users. In order to download a private Slack file using an HTTP GET request, a bot has to provide its token key in a header of the GET request.

 

In this hack, we will use the Apache HttpClient library to perform the HTTP GET call with the correct header. Let’s see how to download a Slack file in Java:

private static String downloadFile(SlackMessagePosted event)
throws IOException {
//creating a simple http client
HttpClient client = HttpClientBuilder.create().build();
// defining a get HTTP request
HttpGet get = new HttpGet(event.getSlackFile().getUrlPrivate());
// adding the Authorization header with the bot token
get.setHeader("Authorization", "Bearer " + TOKEN);
// send the get request
HttpResponse response = client.execute(get);
// initiate a reader to read the response
BufferedReader buffer = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
// collect all the file lines and return the content
return buffer.lines().collect(Collectors.joining("\n"));
}
Format the JSON
As mentioned at the beginning of this hack, we’re going to use JSON-IO to format the JSON data, thanks to its JsonWriter class, which is straightforward:
private static String formatJson(String jsonString) {
return JsonWriter.formatJson(jsonString);
}

 

Send back a new, formatted JSON file

Here we will use the sendFile method provided by the SlackSession class, giving the name of the file and using the prettified JSON string as data:

private static void sendBackPrettifiedFile(SlackMessagePosted event,
SlackSession session, String formattedJson) {
//sending a file to the same direct channel, using the String byte
//array and a new filename: the original filename prefixed with pretty_ as
session.sendFile(event.getChannel(),formattedJson.getBytes(), "pretty_"+event.getSlackFile().getName());
}

 

Handling processor errors

If the file can’t be downloaded or it isn’t a JSON file, an exception will be thrown, and the bot has to notify the user it wasn’t able to process the file. Sending a message is the simplest way to do that:

private static void failOnException(SlackMessagePosted event,
SlackSession session, Exception e) {
//we're responding on the direct channel uing a simple message
// that an issue occured during the file processing
session.sendMessage(event.getChannel(),
"Sorry I was unable to process your file : " + e.getMessage());
}

 

And you’re done. Putting it all together will take less than 100 lines of Java code. You just have to build a JAR with all of the dependencies with the standard tool or your favorite IDE.

 

Let’s look at how this bot behaves. We took the JSON extract we presented during the introduction of this library and removed all of the formattings.  This hack showed you how to build a bot to prettify any JSON posted to it. Let’s now see a hack that dispatches customer support requests through Slack.

 

Dispatch customer support through Slack with Smooch

Thanks to its channel features, Slack is a good way to centralize the communication within your organization. But you can’t invite all of your customers to your Slack team. In most cases, customer support is done through another medium (email, forum, instant messaging).

 

Smooch provides a service that lets you link your customer support tool to a Slack team channel. This is a nice integration, but the channel can be very busy and your customer service department can be quickly mix up messages trying to answer them.

 

A solution to this issue is to add to this Smooch integration a Slack bot that dispatches requests. In this hack, we’ll show you how to integrate Smooch with Slack and add the dispatch bot.

 

Installing Smooch

You first have to create an account on the smooch website.

Here are the steps you’ll need to follow during this creation:

  1. Once your email is confirmed, you will need to configure your smooch account by answering a few questions asked by a robot.
  2. Select the way your customers are reaching your customer support.
  3. Select the solution the customer support team will use to receive customer requests.

 

In this hack, emails are used as the method for reaching customer support. Smooch will create an email address that forwards the messages sent to it to your Slack channel. Alternatively, you can use your own support email by enabling the email forwarding in the smooch configuration screen.

 

By default, on Slack, the messages are sent to the #general channel, but you can choose a different channel in Smooch’s Slack settings

Standard Smooch use case

Now that Smooch is set up, let’s see what happens when you receive a customer support request. Imagine a customer sends an email to customer support:

to: help@acme.com Subject: need help Content :

On Slack, the customer support team receives a message notifying them that the customer sent an email and that a dedicated channel has been created to deal with it 

 

A customer support representative can then answer the customer’s request using the /sk command:

/sk Hello Sir, could you please elaborate? Best regards, John Smith

And the customer instantly receives the following email:

from: help@acme.com Subject : Re: need help Content :

Hello Sir, could you please elaborate? Best regards, John Smith

 

Leveraging Slack’s history feature

The Smooch Slack integration will create a channel for each new user and will auto archive the channel after a specific duration of inactivity (6 hours by default). If the same user sends a new request a week later, the archived channel will be unarchived and all the history from past requests will be kept.

 

Creating customer support dispatcher

Now that you have Smooch up and running, we’re going to create a Slack bot dispatcher in order to distribute the incoming customer support requests.

 

The dispatcher will report who should take care of the incoming customer support requests and send a message to the customer support team member notifying him of the request he or she has to handle. This reduces the risk of having a question go unanswered or having more than one customer service rep responded.

 

The Slack bot will be developed in the Java language using the Simple Slack API library. We won’t detail the Java environment setup procedure since everything will fit into a single class.

Slack bot skeleton
Here is the bot’s skeleton:
private static final String TOKEN = "insert your token here";
public static void main(String [] args) throws Exception {
//creating the session
SlackSession session = SlackSessionFactory.createWebSocketSlackSession(TOKEN);
//adding a message listener to the session
session.addMessagePostedListener(
CustomerSupportDispatcher::processMessagePostedEvent);
//connecting the session to the Slack team
session.connect();
//delegating all the event management to the session
Thread.sleep(Long.MAX_VALUE);
}

As in the previous hack, we reproduce the same main structure as the JSON pretty printer, and all of the interesting code is in the message processor: the processMessagePostedEvent method.

 

Message processor structure

Here’s how the message processor is structured:

private static void processMessagePostedEvent(SlackMessagePosted event,
SlackSession session) {
//filtering all the messages the bot doesn't care about
if (isNotASmoochMessage(event)) {
return;
}
//notifying the CS member
notifyCustomerSupportMember(event,
selectCustomerSupportMember(event,session),
session);
}

The processor is divided into three steps:

  1.  Filter out the messages not coming from Smooch
  2. Select a customer support representative
  3. Notify the rep that he has an incoming request to process

 

Message filtering

In this method, some validation on the event is done to discard events we don’t want to process; verifying the sender’s name and message type should be sufficient:

private static boolean isNotASmoochMessage(SlackMessagePosted event) {
//if the event is not a bot message
if (event.getMessageSubType() != BOT_MESSAGE) {
return true;
}
//if the sender is not named Smooch
if (!"Smooch".equals(event.getSender().getUserName())) {
return true;
}
return false;
}

 

Selecting a customer support rep

For this step we’ve chosen to keep things simple, so the selection will be made randomly among all of the users in the support channel that are not bots and are currently active:

private static SlackUser \ selectCustomerSupportMember(SlackMessagePosted event,
SlackSession session) { SlackChannel channel = event.getChannel(); Collection<SlackUser> users = channel.getMembers(); List<SlackUser> selectableUsers = users.stream()
.filter(user -> !user.isBot() && \ session.getPresence(user) == ACTIVE)
.collect(Collectors.toList());
return selectableUsers.get((int)Math.random()*selectableUsers.size());
}

 

Notifying the rep of an incoming request

In this step, we first get the channel reference that will be used to send messages. Smooch writes this reference in the attachment it posts, so we need to parse the underlying event JSON to get the attachment details. 

 

After this parsing, the Slack bot will send a message to the support channel to notify the other reps that a team member has been selected to handle the issue. It also sends a direct message to the selected team member to inform him/her that he/she has to take care of this request. This code shows the flow that is implemented from the notification to the customer support member:

private static void notifyCustomerSupportMember(SlackMessagePosted event,

SlackUser nominee, SlackSession session) {

String channelReference = getCreatedChannelReference(event); session.sendMessage(event.getChannel(), "<@" + nominee.getId() + ">:" +

" will handle the issue in " + channelReference); session.sendMessageToUser(nominee,

" Could you please handle the issue in " + channelReference,null);

}

This hack showed you how to implement a more complex interaction between your Slack bot and your users. This is a good base to build upon; for example, by adding a persistence layer, you can extend this bot to store interesting statistics like how many requests a support assignee has been asked to handle or the most common keywords in those customer requests.

Now let’s see how to make a training bot.

 

Create a bot to check your multiplication skills

You would probably like to train your brain, so why not have a bot to ask you the results on multiplication tables, measuring the total time you need to give the correct answers on ten multiplication sets? We will produce such a Slack bot in this hack. We’ll do this using the Simple Slack API framework and Java.

 

Slack bot skeleton

This hack uses the same bot skeleton you saw in hack #48. We’re going to create a session, register a message post listener, and connect the session to the Slack server.

Message processor structure Here is the event handler:
private static void processMessagePostedEvent(SlackMessagePosted event,
SlackSession session) {
handleTestTrigger(event, session); handleAnswer(event, session);
}

The processor has to handle two kinds of messages:

  • detecting a keyword to launch the test
  • detecting an answer to a running test

The following sections explain how to do so. Handling test launch requests

 

To launch a test, users have to send a !times command to the bot through a direct message. The bot will then check whether the user is currently running a test, and if not, will store the test variables in a GameSession instance (keeping track of time spent to answer, and some other values). Then it starts the test. Here’s the code that performs all of these steps:

>private static void handleTestTrigger(SlackMessagePosted event,
SlackSession session) {
//trigger is accepted only on direct message to the bot
if (!event.getChannel().isDirect()) {
return;
}
//looking for !times command
if ("!times".equals(event.getMessageContent().trim())) {
// check whether a game is already running with this user,
// and if so, ignore this command
if (gameSessions.containsKey(event.getSender().getId())) {
return;
}
GameSession gameSession = prepareGameSession(event, session); gameSession.timer.start();
sendTimes(gameSession, session);
}
}

 

Handling test answers

Answers are numbers only and are sent on the direct channel between the user and the Slack bot. If the user hasn’t started a test and sends the bot a numeric message, the bot should ignore that message. If a number is given during a test, then the bot will react according to whether the answer is true or false.

Here how these guidelines translate into code:

private static void handleAnswer(SlackMessagePosted event,
SlackSession session) {
//no test launched for this user
GameSession gameSession = gameSessions.get(event.getSender().getId());
if (gameSession == null) {
return;
}
//an answer should be given on a direct channel
if (!event.getChannel().isDirect()) {
return;
}
//an answer is a number
String answerValue = event.getMessageContent().trim();
try {
int resultGiven = Integer.parseInt(answerValue);
if (resultGiven == gameSession.goodResult) {
//correct answer
goodAnswer(event, session, gameSession);
} else {
wrongAnswer(event, session);
}
} catch (NumberFormatException e) {
//ignore the result
return;
}
}

 

Sending a test question

When the test starts or when a user gives a correct answer, the bot randomly selects two numbers between 1 and 10 and sends the multiplication problem to the user as a message:

>private static void sendTimes(GameSession gameSession,
SlackSession session) {
//select two values to multiply
int a = 1 + (int) (Math.random() * 10); int b = 1 + (int) (Math.random() * 10); gameSession.goodResult = a * b;
gameSession.questionTimestamp = session.sendMessageToUser(
gameSession.user, a + " x " + b, null).getReply().getTimestamp();
}

 

Correct answer behavior

The following code tells the bot to indicate a correct answer by pinning a checkmark emoji on it. The bot then computes the time spent to answer and moves to the next test step (either another multiplication problem or the end of the test):

private static void goodAnswer(SlackMessagePosted event, SlackSession session,

GameSession gameSession) { session.addReactionToMessage(event.getChannel(), event.getTimeStamp(),

"white_check_mark"); computeTime(event, gameSession); nextTestStep(session, gameSession);

}

 

Wrong answer behavior

As with a correct answer, the bot pins an emoji to the user’s response, but this time a red X is used to show the user the answer was wrong:

private static void wrongAnswer(SlackMessagePosted event,

SlackSession session) { session.addReactionToMessage(event.getChannel(), event.getTimeStamp(), "x");

}

 

Ending the test

At the end of the test, the Slack bot displays the total time spent to give the ten answers and removes the game session to allow the user to start a new test.

private static void showTestResults(GameSession gameSession,

SlackSession session) { session.sendMessageToUser(gameSession.user, "You took " +

gameSession.cumulativeTime + " seconds to complete the test", null); gameSessions.remove(gameSession.user.getId());

}

In this hack, we saw how to interact with users and maintain a state machine to keep track of the progress of a game. Now, let’s next see how we can use the Simple Slack API to run a “quiz” on a channel.

 

Create a bot to run a quiz on a channel

Your team will likely have a Slack channel dedicated to entertainment, fun or challenges. Why not set up a bot to ask the questions? It could be an impartial referee and it could enforce a time constraint on the responses.

 

This hack—which will be developed in Java—shows you a simple way to develop such a Slack bot using the Simple Slack API framework. The bot will send questions and propose four possibles answers.

 

Any user on the channel can give one answer to each question. The first one to give the right answer is awarded a point. If the right answer is not given within 10 seconds, the bot asks a new question. By the end of the question session, the bot displays a scoreboard for all of the users who have answered at least one question.

 

Slack bot skeleton

This bot uses the same pattern as the previous bot, using a similar framework. There’s one additional step in this hack—loading the quiz questions—but that is not really related to Slack. It is just a matter of retrieving question definitions from a JSON file.

 

The main entry point looks like this:

 public static void main(String[] args) throws Exception {
//loading allQuestions
allQuestions = loadQuestions();
//creating the session
SlackSession session = SlackSessionFactory.createWebSocketSlackSession(TOKEN);
//adding a message listener to the session
session.addMessagePostedListener(QuizzBot::processMessagePostedEvent);
//connecting the session to the Slack team
session.connect();
//delegating all the event management to the session
Thread.sleep(Long.MAX_VALUE);
}
Message processor structure
The processor has to handle two kinds of messages: requests for a quiz and answers during a quiz. Here’s the code that lets it do so:
private static void processMessagePostedEvent(SlackMessagePosted event,
SlackSession session) {
handleQuizzRequest(event, session); handleAnswer(event, session);
}

 

Handling quiz requests

Quiz requests are triggered using !quiz. The event handler below will first check whether the message contains this keyword. If the keyword is found, then the bot has to check whether it is already running a quiz.

 

If so, it asks the user who requested a quiz to wait (the bot can handle only one quiz at a time). If no quiz is currently run, then the bot prepares the quiz data (randomly choosing questions and preparing the scoreboard) to send the first question.

private static void handleQuizzRequest(SlackMessagePosted event, SlackSession session) {
//looking for !quizz command
if ("!quizz".equals(event.getMessageContent().trim())) {
// check if a quiz is currently in progress on a channel
if (quizzChannel != null) {
session.sendMessage(event.getChannel(), "I'm sorry " + event.getSender().getRe ", I'm currently running a quiz, please
wait a few minutes");
return;
}
prepareQuizzData(event); sendNewQuestion(session);
}
}

 

Handling quiz answers

Quiz answers are digits between 1 and 4; any other values are ignored. Whatever the answer is given, the respondent’s user ID is stored in order to avoid having one user give two answers.

 

Depending on whether the answer is right or wrong, the bot will either give a point to the user and trigger the next question or indicate to the user that it was a wrong answer. Here’s the code that handles all of this:

private static void handleAnswer(SlackMessagePosted event, SlackSession session) {
//no quiz launched
if (quizzChannel == null) {
return;
}
//an answer should be given on the quiz channel only
if (!event.getChannel().getId().equals(quizzChannel.getId())) {
return;
}
//an answer is a single digit from 1 to 4
String answerValue = event.getMessageContent().trim();
if (!ACCEPTED_ANSWERS.contains(answerValue)) {
//ignore answer
return;
}
int currentCounter = questionCounter;
synchronized (lock) {
if (questionCounter != currentCounter) {
// the question has timed out and the next one was sent by the bot
return;
}
//A user can answer only once per question
if (answeredUser.contains(event.getSender().getId())) { session.sendMessage(quizzChannel, "I'm sorry " +
event.getSender().getRealName() +
", you can only give one answer per question");
return;
}
//This user has now given an answer
answeredUser.add(event.getSender().getId());
//Check value
if (Integer.parseInt(answerValue) == expectedAnswer) {
//good answer
goodAnswer(event, session);
} else {
wrongAnswer(event, session);
}
}
}

 

Sending a new question

When the quiz starts or when a player gives a correct answer, the bot sends a new question. To achieve that, the bot picks from its randomized question list and prepares a Slack attachment to nicely format the question.

 

Then it sends the question on Slack and starts a timer to wait up to 10 seconds; if no correct answer is given by the time the 10 seconds run out, the bot sends a new question. Here’s the code that does all of this:

private static void sendNewQuestion(SlackSession session) {
//resetting the users who have answered to this question
answeredUser = new HashSet<>();
Question currentQuestion = shuffledQuestions.get(questionCounter);
expectedAnswer = currentQuestion.expectedAnswer;
SlackAttachment attachment = new SlackAttachment(currentQuestion. question,
currentQuestion. question, "", "");
attachment.addField("1", currentQuestion.answer1, true); attachment.addField("2", currentQuestion.answer2, true); attachment.addField("3", currentQuestion.answer3, true); attachment.addField("4", currentQuestion.answer4, true); session.sendMessage(quizzChannel, "", attachment);
timer = buildTimer(session); timer.start();
}

 

Handling a correct answer

When a player chooses the right answer, the timer is interrupted and a point is given to the player. Next, the bot tells the user he gave the right answer and triggers the next step: either posting either a new question or (if that was the last question) the final results of the quiz. Here’s the code that handles that:

private static void goodAnswer(SlackMessagePosted event, SlackSession session) {

timer.interrupt(); increaseScore(event);

session.sendMessage(quizzChannel, "Good answer " + event.getSender().getRealName());

nextQuizzStep(session);

}

 

Handling the wrong answer

When someone makes an incorrect guess, that player is registered in the scoreboard, since he has participated; even if the answer is wrong his score will be displayed at the end of the quiz. Then a message is sent to that used to tell him that his answer was wrong. Here’s the code that accomplishes these two steps:

private static void wrongAnswer(SlackMessagePosted event, SlackSession session) {

registerPlayerInScoreBoard(event); session.sendMessage(quizzChannel, "I'm sorry, you're wrong " +

event.getSender().getRealName());

}

 

Displaying the quiz result

The score is stored in a map associating the player’s user id to his score, so the bot adds a field for each participating player. The bot then sends the attachment with an empty message, and finally resets questions and the quiz channel variable so a new quiz can be requested:

private static void showResults(SlackSession session) { SlackAttachment attachment = new SlackAttachment("Final score",
"Final score", "", ""); for (Map.Entry<String, Integer> entry : score.entrySet()) { attachment.addField(session.findUserById(entry.getKey()).getRealName(),
entry.getValue().toString(), true);
}
session.sendMessage(quizzChannel, "", attachment); shuffledQuestions = null;
quizzChannel = null;
}

In all of the Java Slack bots presented in this blog, you’ve seen how to send messages, read files, create files, and pin reaction emojis. This is a good start to give you some ideas to implement your own hacks.

 

Through integrations, extensions, and bots, we have pointed you in the right direction so you can take advantage of your own Slack implementation.

Recommend