Skip to content

Commit a55fdf4

Browse files
committed
slack webhooks, bot, command test
1 parent 368255e commit a55fdf4

File tree

10 files changed

+406
-33
lines changed

10 files changed

+406
-33
lines changed

springboot-bot-demo/pom.xml

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
55
<modelVersion>4.0.0</modelVersion>
66
<parent>
77
<groupId>org.springframework.boot</groupId>
@@ -24,10 +24,12 @@
2424
<groupId>org.springframework.boot</groupId>
2525
<artifactId>spring-boot-starter-data-jpa</artifactId>
2626
</dependency>
27+
2728
<dependency>
2829
<groupId>org.springframework.boot</groupId>
2930
<artifactId>spring-boot-starter-thymeleaf</artifactId>
3031
</dependency>
32+
3133
<dependency>
3234
<groupId>org.springframework.boot</groupId>
3335
<artifactId>spring-boot-starter-web</artifactId>

springboot-bot-demo/src/main/java/demo/DemoApplication.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55
import org.springframework.core.io.ClassPathResource;
66

7-
@SpringBootApplication
7+
@SpringBootApplication(scanBasePackages = {"me.ramswaroop.jbot", "demo"})
88
public class DemoApplication {
99

1010
public static void main(String[] args) throws Exception {

springboot-bot-demo/src/main/java/demo/configuration/SlackConfiguration.java

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package demo.configuration;
22

3+
import demo.configuration.properties.SlackProperties;
34
import javax.annotation.PostConstruct;
45
import lombok.extern.slf4j.Slf4j;
56
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7+
import org.springframework.context.annotation.Bean;
68
import org.springframework.context.annotation.Configuration;
79

810
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package demo.configuration.properties;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
import lombok.ToString;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.beans.factory.annotation.Value;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10+
import org.springframework.stereotype.Component;
11+
12+
/**
13+
* Slack properties
14+
*
15+
* @author zacconding
16+
* @Date 2019-01-16
17+
* @GitHub : https://github.com/zacscoding
18+
*/
19+
@Slf4j
20+
@Getter
21+
@Setter
22+
@ToString
23+
@Component
24+
@ConditionalOnProperty(name = "slack.enabled", havingValue = "true")
25+
public class SlackProperties {
26+
27+
private String slackApi;
28+
private String slackBotToken;
29+
private String slashCommandToken;
30+
private String slackIncomingWebhookUrl;
31+
32+
@Autowired
33+
public SlackProperties(@Value("${slackApi}") String slackApi,
34+
@Value("${slackBotToken}") String slackBotToken,
35+
@Value("${slashCommandToken}") String slashCommandToken,
36+
@Value("${slackIncomingWebhookUrl}") String slackIncomingWebhookUrl) {
37+
38+
this.slackApi = slackApi;
39+
this.slackBotToken = slackBotToken;
40+
this.slashCommandToken = slashCommandToken;
41+
this.slackIncomingWebhookUrl = slackIncomingWebhookUrl;
42+
log.info("## Slack :: {}", this);
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package demo.server;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
import lombok.Setter;
8+
import lombok.ToString;
9+
10+
/**
11+
* @author zacconding
12+
* @Date 2019-01-16
13+
* @GitHub : https://github.com/zacscoding
14+
*/
15+
@Getter
16+
@Setter
17+
@ToString
18+
@NoArgsConstructor
19+
@AllArgsConstructor
20+
@Builder
21+
public class Server {
22+
23+
private String serviceName;
24+
private String working;
25+
private String lastHeartbeat;
26+
}
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,137 @@
11
package demo.slack;
22

3-
3+
import demo.configuration.properties.SlackProperties;
4+
import java.util.regex.Matcher;
5+
import lombok.extern.slf4j.Slf4j;
6+
import me.ramswaroop.jbot.core.common.Controller;
7+
import me.ramswaroop.jbot.core.common.EventType;
8+
import me.ramswaroop.jbot.core.common.JBot;
49
import me.ramswaroop.jbot.core.slack.Bot;
10+
import me.ramswaroop.jbot.core.slack.models.Event;
11+
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.stereotype.Component;
13+
import org.springframework.web.socket.WebSocketSession;
514

615
/**
7-
* @author zacconding
8-
* @Date 2019-01-16
9-
* @GitHub : https://github.com/zacscoding
16+
* https://github.com/rampatra/jbot/blob/master/jbot-example/src/main/java/example/jbot/slack/SlackBot.java
1017
*/
11-
18+
@Slf4j
19+
@JBot
20+
@Component
1221
public class SlackBot extends Bot {
1322

23+
/**
24+
* Slack token from application.properties file. You can get your slack token next <a
25+
* href="https://my.slack.com/services/new/bot">creating a new bot</a>.
26+
*/
27+
private SlackProperties slackProperties;
28+
29+
@Autowired
30+
public SlackBot(SlackProperties slackProperties) {
31+
this.slackProperties = slackProperties;
32+
}
33+
1434
@Override
1535
public String getSlackToken() {
16-
return null;
36+
return slackProperties.getSlackBotToken();
1737
}
1838

1939
@Override
2040
public Bot getSlackBot() {
21-
return null;
41+
return this;
42+
}
43+
44+
/**
45+
* Invoked when the bot receives a direct mention (@botname: message) or a direct message. NOTE: These two event
46+
* types are added by jbot to make your task easier, Slack doesn't have any direct way to determine these type of
47+
* events.
48+
*/
49+
@Controller(events = {EventType.DIRECT_MENTION, EventType.DIRECT_MESSAGE})
50+
public void onReceiveDM(WebSocketSession session, Event event) {
51+
log.info("## receive DM. event :: {}", event.getText());
52+
reply(session, event, "Hi, I am " + slackService.getCurrentUser().getName());
53+
}
54+
55+
/**
56+
* Invoked when bot receives an event of type message with text satisfying the pattern {@code ([a-z ]{2})(\d+)([a-z
57+
* ]{2})}. For example, messages like "ab12xy" or "ab2bc" etc will invoke this method.
58+
*/
59+
@Controller(events = EventType.MESSAGE, pattern = "^([a-z ]{2})(\\d+)([a-z ]{2})$")
60+
public void onReceiveMessage(WebSocketSession session, Event event, Matcher matcher) {
61+
log.info("## Receive message : {}", event.getText());
62+
reply(session, event, "First group: " + matcher.group(0) + "\n" +
63+
"Second group: " + matcher.group(1) + "\n" +
64+
"Third group: " + matcher.group(2) + "\n" +
65+
"Fourth group: " + matcher.group(3));
66+
}
67+
68+
/**
69+
* Invoked when an item is pinned in the channel.
70+
*/
71+
@Controller(events = EventType.PIN_ADDED)
72+
public void onPinAdded(WebSocketSession session, Event event) {
73+
log.info("## pin added : {}", event.getText());
74+
reply(session, event, "Thanks for the pin! You can find all pinned items under channel details.");
75+
}
76+
77+
/**
78+
* Invoked when bot receives an event of type file shared. NOTE: You can't reply to this event as slack doesn't send
79+
* a channel id for this event type. You can learn more about
80+
* <a href="https://api.slack.com/events/file_shared">file_shared</a>
81+
* event from Slack's Api documentation.
82+
*/
83+
@Controller(events = EventType.FILE_SHARED)
84+
public void onFileShared(WebSocketSession session, Event event) {
85+
log.info("File shared: {}", event);
86+
}
87+
88+
89+
/**
90+
* Conversation feature of JBot. This method is the starting point of the conversation (as it calls {@link
91+
* Bot#startConversation(Event, String)} within it. You can chain methods which will be invoked one after the other
92+
* leading to a conversation. You can chain methods with {@link Controller#next()} by specifying the method name to
93+
* chain with.
94+
*/
95+
@Controller(pattern = "(setup meeting)", next = "confirmTiming")
96+
public void setupMeeting(WebSocketSession session, Event event) {
97+
startConversation(event, "confirmTiming"); // start conversation
98+
reply(session, event, "Cool! At what time (ex. 15:30) do you want me to set up the meeting?");
99+
}
100+
101+
/**
102+
* This method will be invoked after {@link SlackBot#setupMeeting(WebSocketSession, Event)}.
103+
*/
104+
@Controller(next = "askTimeForMeeting")
105+
public void confirmTiming(WebSocketSession session, Event event) {
106+
reply(session, event, "Your meeting is set at " + event.getText() +
107+
". Would you like to repeat it tomorrow?");
108+
nextConversation(event); // jump to next question in conversation
109+
}
110+
111+
/**
112+
* This method will be invoked after {@link SlackBot#confirmTiming(WebSocketSession, Event)}.
113+
*/
114+
@Controller(next = "askWhetherToRepeat")
115+
public void askTimeForMeeting(WebSocketSession session, Event event) {
116+
if (event.getText().contains("yes")) {
117+
reply(session, event, "Okay. Would you like me to set a reminder for you?");
118+
nextConversation(event); // jump to next question in conversation
119+
} else {
120+
reply(session, event, "No problem. You can always schedule one with 'setup meeting' command.");
121+
stopConversation(event); // stop conversation only if user says no
122+
}
123+
}
124+
125+
/**
126+
* This method will be invoked after {@link SlackBot#askTimeForMeeting(WebSocketSession, Event)}.
127+
*/
128+
@Controller
129+
public void askWhetherToRepeat(WebSocketSession session, Event event) {
130+
if (event.getText().contains("yes")) {
131+
reply(session, event, "Great! I will remind you tomorrow before the meeting.");
132+
} else {
133+
reply(session, event, "Okay, don't forget to attend the meeting tomorrow :)");
134+
}
135+
stopConversation(event); // stop conversation
22136
}
23137
}

springboot-bot-demo/src/main/java/demo/slack/SlackNotifier.java

-23
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package demo.slack;
2+
3+
4+
import com.fasterxml.jackson.core.JsonProcessingException;
5+
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import lombok.extern.slf4j.Slf4j;
7+
import me.ramswaroop.jbot.core.slack.models.Attachment;
8+
import me.ramswaroop.jbot.core.slack.models.RichMessage;
9+
import org.aspectj.weaver.ast.Test;
10+
import org.springframework.beans.factory.annotation.Value;
11+
import org.springframework.http.MediaType;
12+
import org.springframework.web.bind.annotation.RequestMapping;
13+
import org.springframework.web.bind.annotation.RequestMethod;
14+
import org.springframework.web.bind.annotation.RequestParam;
15+
import org.springframework.web.bind.annotation.RestController;
16+
17+
/**
18+
* https://github.com/rampatra/jbot/blob/master/jbot-example/src/main/java/example/jbot/slack/SlackSlashCommand.java
19+
*/
20+
@Slf4j
21+
@RestController
22+
public class SlackSlashCommand {
23+
24+
/**
25+
* The token you get while creating a new Slash Command. You should paste the token in application.properties file.
26+
*/
27+
@Value("${slashCommandToken}")
28+
private String slackToken;
29+
30+
31+
/**
32+
* Slash Command handler. When a user types for example "/app help" then slack sends a POST request to this
33+
* endpoint. So, this endpoint should match the url you set while creating the Slack Slash Command.
34+
*/
35+
@RequestMapping(value = "/**",
36+
method = RequestMethod.POST,
37+
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
38+
public RichMessage onReceiveSlashCommand(
39+
@RequestParam("token") String token,
40+
@RequestParam("team_id") String teamId,
41+
@RequestParam("team_domain") String teamDomain,
42+
@RequestParam("channel_id") String channelId,
43+
@RequestParam("channel_name") String channelName,
44+
@RequestParam("user_id") String userId,
45+
@RequestParam("user_name") String userName,
46+
@RequestParam("command") String command,
47+
@RequestParam("text") String text,
48+
@RequestParam("response_url") String responseUrl) {
49+
50+
log.info("token : {}\nteam_id : {}\nchannel_id : {}\nchannel_name : {}\nuser_id : {}\n"
51+
+ "user_name : {}\ncommand : {} \ntext : {}\nresponse_url : {}\n"
52+
, token, teamId, teamDomain, channelId, channelName, userId, userName, command, text, responseUrl
53+
);
54+
55+
// validate token
56+
if (!token.equals(slackToken)) {
57+
return new RichMessage("Sorry! You're not lucky enough to use our slack command.");
58+
}
59+
60+
/** build response */
61+
RichMessage richMessage = new RichMessage("The is Slash Commander!");
62+
richMessage.setResponseType("in_channel");
63+
// set attachments
64+
Attachment[] attachments = new Attachment[1];
65+
attachments[0] = new Attachment();
66+
attachments[0].setText("I will perform all tasks for you.");
67+
richMessage.setAttachments(attachments);
68+
69+
// For debugging purpose only
70+
if (log.isDebugEnabled()) {
71+
try {
72+
log.debug("Reply (RichMessage): {}", new ObjectMapper().writeValueAsString(richMessage));
73+
} catch (JsonProcessingException e) {
74+
log.debug("Error parsing RichMessage: ", e);
75+
}
76+
}
77+
78+
return richMessage.encodedMessage(); // don't forget to send the encoded message to Slack
79+
}
80+
81+
82+
}

0 commit comments

Comments
 (0)