diff --git a/.gitignore b/.gitignore
index b7a97db..8c3a071 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
*.iml
target
.secret
+dependency-reduced-pom.xml
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..4408a99
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "src/main/resources/AcroBot"]
+ path = src/main/resources/AcroBot
+ url = https://github.com/theacrobot/AcroBot.git
diff --git a/pom.xml b/pom.xml
index b9b9c83..1d1948f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,10 +12,11 @@
UTF-8
1.8
1.8
- 2.9.10.3
+ 2.9.10.4
1.25.0
1.70.0
4.3.6.Final
+ 1.26
@@ -38,6 +39,12 @@
${jackson.version}
+
+ org.yaml
+ snakeyaml
+ ${snakeyaml.version}
+
+
diff --git a/sec b/sec
new file mode 100644
index 0000000..d840a65
Binary files /dev/null and b/sec differ
diff --git a/src/main/java/com/redhat/constants/Constants.java b/src/main/java/com/redhat/constants/Constants.java
index b55d149..cc7bbff 100644
--- a/src/main/java/com/redhat/constants/Constants.java
+++ b/src/main/java/com/redhat/constants/Constants.java
@@ -4,9 +4,8 @@ public class Constants {
public static final String CREDENTIALS_PATH_ENV_PROPERTY = "GOOGLE_APPLICATION_CREDENTIALS";
public static final String PROJECT_ID = System.getenv("PROJECT_ID");
public static final String SUBSCRIPTION_ID = System.getenv("SUBSCRIPTION_ID");
- public static final String SUDO_PASSWORD = System.getenv("SUDO_PASSWORD");
public static final String HANGOUTS_CHAT_API_SCOPE = "https://www.googleapis.com/auth/chat.bot";
-
+ public static final String YAML_SOURCE = "AcroBot/data/abbrev.yaml"; // ClassLoader path
// Response templates
public static final String RESPONSE_URL_TEMPLATE = "https://chat.googleapis.com/v1/__SPACE_ID__/messages";
public static final String ADDED_RESPONSE = "Thank you for adding me! Send `@Acrobot help` for more information about me.";
@@ -30,5 +29,19 @@ public class Constants {
"All of the actions work in a direct message without tagging `@Acrobot`. Whitespaces shouldn't matter," +
"and you can input acronym in both lower- and uppercase; it will be matched regardless of the capitalisation. \n\n" +
"Acrobot is implemented by Marek Czernek. You can find documentation and file issues or suggest improvements at " +
- "https://github.com/m-czernek/acrobot";
+ "https://github.com/m-czernek/acrobot \n\n" +
+ "Currently, Acrobot is testing injecting IRC acronym database into the results. For feedback, comments, or suggestions "+
+ "about the function, visit https://github.com/m-czernek/acrobot/pull/12";
+
+ public static final String FOUND_YAML_TEXT = "\n\n_Found requested acronym in the IRC database. " +
+ "Send @Acrobot help for more information about this feature._\n";
+
+ // we should not return null for sudo password
+ private static final String SUDO_PASSWORD = System.getenv("SUDO_PASSWORD");
+ public static String getSudoPassword(String defaultValue) {
+ if(SUDO_PASSWORD == null) {
+ return defaultValue;
+ }
+ return SUDO_PASSWORD;
+ }
}
diff --git a/src/main/java/com/redhat/constants/MessageType.java b/src/main/java/com/redhat/constants/MessageType.java
new file mode 100644
index 0000000..98544a8
--- /dev/null
+++ b/src/main/java/com/redhat/constants/MessageType.java
@@ -0,0 +1,17 @@
+package com.redhat.constants;
+
+public enum MessageType {
+ ADDED_TO_ROOM(Constants.ADDED_RESPONSE),
+ SUDO_RESPONSE("SUDO_PASSWORD"),
+ INVALID_MESSAGE(Constants.INCORRECT_FORMAT_FOR_SAVING_ACRONYM),
+ HELP(Constants.HELP_TEXT),
+ UPDATE_OR_REMOVE("UPDATE_REMOVE"),
+ SAVE_OR_MERGE("SAVE_MERGE"),
+ GET_ACRONYM("GET_ACRONYM");
+
+ public final String eventType;
+
+ private MessageType(String eventType) {
+ this.eventType = eventType;
+ }
+}
diff --git a/src/main/java/com/redhat/messages/AcroBot.java b/src/main/java/com/redhat/messages/AcroBot.java
index c9a9ef5..60efebb 100644
--- a/src/main/java/com/redhat/messages/AcroBot.java
+++ b/src/main/java/com/redhat/messages/AcroBot.java
@@ -16,6 +16,7 @@
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.pubsub.v1.PubsubMessage;
import com.redhat.constants.Constants;
+import com.redhat.constants.MessageType;
import java.io.FileInputStream;
import java.util.Collections;
@@ -27,6 +28,7 @@ public class AcroBot implements MessageReceiver {
private HttpTransport httpTransport;
private HttpRequestFactory requestFactory;
private MessageHelper helper;
+ private YamlAcrobotInjector yamlAcrobotInjector;
public AcroBot() throws Exception {
credential = GoogleCredential
@@ -35,6 +37,7 @@ public AcroBot() throws Exception {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
requestFactory = httpTransport.createRequestFactory(credential);
helper = new MessageHelper();
+ yamlAcrobotInjector = new YamlAcrobotInjector();
}
// Called when a message is received by the subscriber.
@@ -68,7 +71,13 @@ public void handle(JsonNode eventJson) throws Exception {
break;
}
case "MESSAGE":
- responseNode.put("text", helper.handleMessageAction(eventJson));
+ String response = helper.handleMessageAction(eventJson);
+
+ if(MessageTypeHelper.determineMessageAction(eventJson) == MessageType.GET_ACRONYM) {
+ response = yamlAcrobotInjector.injectYamlAcronyms(eventJson, response);
+ }
+
+ responseNode.put("text", response);
// In case of message, post the response in the same thread.
ObjectNode threadNode = jsonNodeFactory.objectNode();
diff --git a/src/main/java/com/redhat/messages/MessageHelper.java b/src/main/java/com/redhat/messages/MessageHelper.java
index 49b74b0..312c586 100644
--- a/src/main/java/com/redhat/messages/MessageHelper.java
+++ b/src/main/java/com/redhat/messages/MessageHelper.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.redhat.constants.Constants;
+import com.redhat.constants.MessageType;
import com.redhat.entities.Acronym;
import com.redhat.entities.Explanation;
import com.redhat.persistence.AcronymExplanationDal;
@@ -15,41 +16,29 @@ public class MessageHelper {
private AcronymExplanationDal acronymExplanationDal = new AcronymExplanationDal();
public String handleMessageAction(JsonNode eventJson) {
- String resp;
- String message;
String authorEmail = eventJson.get("user").get("email").asText();
+ MessageType type = MessageTypeHelper.determineMessageAction(eventJson);
- try {
- message = eventJson.get("message").get("argumentText").asText().trim();
- } catch (NullPointerException e) {
- // Acrobot was added via mention to a room, and has no argument text
- return Constants.ADDED_RESPONSE;
- }
-
- if(message.startsWith(Constants.SUDO_PASSWORD)) {
- return AdministrativeMessageHelper.handleAdminMessage(message);
+ if(type == MessageType.ADDED_TO_ROOM) {
+ return type.eventType;
}
- if(message.startsWith("!")) {
- message = message.substring(1);
-
- // Validate message
- if (!isMessageValid(message)) {
- return Constants.INCORRECT_FORMAT_FOR_SAVING_ACRONYM;
- }
-
- if(message.contains("=>")) {
- resp = updateOrRemoveExplanation(message, authorEmail);
- } else {
- resp = saveOrMergeAcronym(message, authorEmail);
- }
-
- } else if (message.equals("help")) {
- resp = Constants.HELP_TEXT;
- } else {
- resp = getAcronymAsString(message);
+ String message = eventJson.get("message").get("argumentText").asText().trim();
+
+ switch (type){
+ case SUDO_RESPONSE:
+ return AdministrativeMessageHelper.handleAdminMessage(message);
+ case UPDATE_OR_REMOVE:
+ // Message starts with "!"
+ return updateOrRemoveExplanation(message.substring(1), authorEmail);
+ case SAVE_OR_MERGE:
+ // Message starts with "!"
+ return saveOrMergeAcronym(message.substring(1), authorEmail);
+ case GET_ACRONYM:
+ return getAcronymAsString(message);
+ default:
+ return type.eventType;
}
- return resp;
}
private String updateOrRemoveExplanation(String message, String authorEmail) {
@@ -102,10 +91,6 @@ private String saveOrMergeAcronym(String message, String authorEmail) {
return resp;
}
- private boolean isMessageValid(String message) {
- return message.contains("=") && (!message.trim().endsWith("="));
- }
-
private String[] splitMessageToSaveAndTrim(String message) {
return trimArray(message.split("=", 2));
}
diff --git a/src/main/java/com/redhat/messages/MessageTypeHelper.java b/src/main/java/com/redhat/messages/MessageTypeHelper.java
new file mode 100644
index 0000000..d17cc68
--- /dev/null
+++ b/src/main/java/com/redhat/messages/MessageTypeHelper.java
@@ -0,0 +1,48 @@
+package com.redhat.messages;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.redhat.constants.Constants;
+import com.redhat.constants.MessageType;
+
+public class MessageTypeHelper {
+
+ public static MessageType determineMessageAction(JsonNode eventJson) {
+ final JsonNode msgNode = eventJson.get("message").get("argumentText");
+
+ if(msgNode == null) {
+ // Acrobot was added via mention to a room, and has no argument text
+ return MessageType.ADDED_TO_ROOM;
+ }
+
+ String message = msgNode.asText();
+
+ if(message.startsWith(Constants.getSudoPassword("PW does not exist"))) {
+ return MessageType.SUDO_RESPONSE;
+ }
+
+ if(message.startsWith("!")) {
+ message = message.substring(1);
+
+ // Validate message
+ if (!isMessageValid(message)) {
+ return MessageType.INVALID_MESSAGE;
+ }
+
+ if(message.contains("=>")) {
+ return MessageType.UPDATE_OR_REMOVE;
+ } else {
+ return MessageType.SAVE_OR_MERGE;
+ }
+ }
+
+ if (message.equals("help")) {
+ return MessageType.HELP;
+ } else {
+ return MessageType.GET_ACRONYM;
+ }
+ }
+
+ private static boolean isMessageValid(String message) {
+ return message.contains("=") && (!message.trim().endsWith("="));
+ }
+}
diff --git a/src/main/java/com/redhat/messages/YamlAcrobotInjector.java b/src/main/java/com/redhat/messages/YamlAcrobotInjector.java
new file mode 100644
index 0000000..36a362a
--- /dev/null
+++ b/src/main/java/com/redhat/messages/YamlAcrobotInjector.java
@@ -0,0 +1,32 @@
+package com.redhat.messages;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.redhat.constants.Constants;
+import com.redhat.entities.Acronym;
+import com.redhat.entities.Explanation;
+import com.redhat.persistence.YamlDal;
+
+import java.util.Set;
+
+public class YamlAcrobotInjector {
+ private YamlDal dal = new YamlDal();
+
+ public String injectYamlAcronyms(JsonNode eventJson, String originalMessage) {
+ String res = Constants.FOUND_YAML_TEXT;
+ String requestedAcronym = eventJson.get("message").get("argumentText").asText().trim();
+ Set yamlAcronyms = dal.getAcronymsByName(requestedAcronym);
+
+ if(yamlAcronyms.isEmpty()) {
+ return originalMessage;
+ }
+
+
+ for(Acronym a : yamlAcronyms) {
+ for(Explanation e : a.getExplanations()) {
+ res += e.getExplanation() + "\n";
+ }
+ }
+
+ return originalMessage + res;
+ }
+}
diff --git a/src/main/java/com/redhat/persistence/YamlDal.java b/src/main/java/com/redhat/persistence/YamlDal.java
new file mode 100644
index 0000000..f4bbc2c
--- /dev/null
+++ b/src/main/java/com/redhat/persistence/YamlDal.java
@@ -0,0 +1,56 @@
+package com.redhat.persistence;
+
+import com.redhat.constants.Constants;
+import com.redhat.entities.Acronym;
+import com.redhat.entities.Explanation;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+import org.yaml.snakeyaml.resolver.Resolver;
+
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class YamlDal {
+ private Map> yamlDatabase;
+
+
+ public YamlDal() {
+ InputStream is = this.getClass()
+ .getClassLoader()
+ .getResourceAsStream(Constants.YAML_SOURCE);
+ this.yamlDatabase = new Yaml(new Constructor(), new Representer(),
+ new DumperOptions(), new CustomResolver())
+ .load(is);
+ }
+
+ public Set getAcronymsByName(String name) {
+ Set res = new HashSet<>();
+ for(String key : yamlDatabase.keySet()) {
+ Map databaseSection = yamlDatabase.get(key);
+ if(databaseSection.containsKey(name)) {
+ Acronym a = new Acronym(name);
+ Set e = new HashSet<>();
+ e.add(new Explanation(databaseSection.get(name)));
+ a.setExplanations(e);
+ res.add(a);
+ }
+ }
+ return res;
+ }
+
+ // Custom resolver such that we don't have implicit number -> Integer or
+ // number -> Float typing. We want String or null values only.
+ private class CustomResolver extends Resolver {
+ protected void addImplicitResolvers() {
+ addImplicitResolver(Tag.MERGE, MERGE, "<");
+ addImplicitResolver(Tag.NULL, EMPTY, null);
+ }
+
+ }
+}
+
diff --git a/src/main/resources/AcroBot b/src/main/resources/AcroBot
new file mode 160000
index 0000000..3eb87d2
--- /dev/null
+++ b/src/main/resources/AcroBot
@@ -0,0 +1 @@
+Subproject commit 3eb87d2319f535c6195cd7b9dd061926e1fef2cd
diff --git a/src/test/java/com/redhat/YmlLayerTest.java b/src/test/java/com/redhat/YmlLayerTest.java
new file mode 100644
index 0000000..fc50d46
--- /dev/null
+++ b/src/test/java/com/redhat/YmlLayerTest.java
@@ -0,0 +1,34 @@
+package com.redhat;
+
+import com.redhat.persistence.YamlDal;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+
+public class YmlLayerTest {
+ private YamlDal dal = new YamlDal();
+ // Corner cases
+ // Acro is a number
+ private static String numberAcro = "82576";
+ private static String numberAcroExplanation = "Intel 82576 Gigabit Ethernet Controller";
+ // Acro has starts with a lowercase char
+ private static String lowerCaseAcro = "dNAT";
+ private static String lowerCaseAcroExplanation = "Dynamic Network Address Translation @networking";
+ // Acro contains special chars
+ private static String specialCharAcro = "SMI-S";
+ private static String specialCharAcroExplanation = "Storage Management Initiative Specification";
+
+ @Test
+ public void testCornerCases() {
+ Assertions.assertThat(dal.getAcronymsByName(numberAcro))
+ .hasSize(1)
+ .filteredOn(acronym -> acronym.getExplanations().contains(numberAcroExplanation));
+ Assertions.assertThat(dal.getAcronymsByName(lowerCaseAcro))
+ .hasSize(1)
+ .filteredOn(acronym -> acronym.getExplanations().contains(lowerCaseAcroExplanation));
+ Assertions.assertThat(dal.getAcronymsByName(specialCharAcro))
+ .hasSize(1)
+ .filteredOn(acronym -> acronym.getExplanations().contains(specialCharAcroExplanation));
+ Assertions.assertThat(dal.getAcronymsByName("NON_EXISTENT")).isEmpty();
+ }
+}