diff --git a/README.md b/README.md index 395350e..b53831b 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,83 @@ # HW Week 3 - SLACK BOT CHALLENGE 🤖 !!!
-A [Slack bot](https://api.slack.com/bot-users) is a non-human "user" that interacts with the Slack messaging app. Bots might post messages to users or to channels, send reminders, look up information in response to a question or perform a calculation. In this project, we'll work in teams to build bots that can preform simple interactions with the AccessCode3-3 Slack. +A [Slack bot](https://api.slack.com/bot-users) is a non-human "user" that interacts with the Slack messaging app. +Bots might post messages to users or to channels, send reminders, look up information in response to a question +or perform a calculation. In this project, we'll work in teams to build bots that can preform simple +interactions with the AccessCode3-3 Slack. ![slack bot example](https://api.slack.com/img/api/guide_bot_user.png) -Slack offers three different APIs that developers can use to interact with their service: the Web API, the Real Time Messaging API and the Events API . In this project, bots will only interact using the [Web API](https://api.slack.com/web). The Web API offers methods that can be used to list AccessCode3-3 channels, view message history on a given channel, and post and delete messages on the #bots channel. +Slack offers three different APIs that developers can use to interact with their service: +the Web API, the Real Time Messaging API and the Events API . In this project, bots will only interact using +the [Web API](https://api.slack.com/web). The Web API offers methods that can be used to list AccessCode3-3 channels, + + + +view message history on a given channel, and post and delete messages on the #bots channel. + + +
## Setup The following setup steps only need to be completed **once per team**: -1. Fork and clone [this repo](https://github.com/ramonaharrison/SlackBot). Make sure both team members are added as contributors to the forked repo. +1. Fork and clone [this repo](https://github.com/ramonaharrison/SlackBot). +Make sure both team members are added as contributors to the forked repo. -2. Go to https://accesscode3-3.slack.com/apps/new/A0F7YS25R-bots. Make sure you are signed into the AccessCode3-3 Slack team. Choose a username for your bot and click the "Add bot integration" button. +2. Go to https://accesscode3-3.slack.com/apps/new/A0F7YS25R-bots. +Make sure you are signed into the AccessCode3-3 Slack team. +Choose a username for your bot and click the "Add bot integration" button. -3. Make a note of your **API token**. The token must always be kept in a **safe, secret** place. We will be storing our API keys in the `../SlackBot/api_token.txt` file, which has been added to our `.gitignore` file. +3. Make a note of your **API token**. The token must always be kept in a **safe, secret** place. +We will be storing our API keys in the `../SlackBot/api_token.txt` file, +which has been added to our `.gitignore` file. - > Always be careful when sharing API tokens! Be careful to never publish +>Always be careful when sharing API tokens! Be careful to never publish > our bot user tokens in any public GitHub code repository. -4. Complete your bot's profile. Add an avatar image/emoji, a first and last name and a description of what your bot does. When you are finished, click the "Save Integration" button. +4. Complete your bot's profile. Add an avatar image/emoji, a first and last name and a description +of what your bot does. When you are finished, click the "Save Integration" button. + +5. **Both team members:** join the #bots channel on Slack so you can see what your bot is up to. -5. **Both team members:** join the #bots channel on Slack so you can see what your bot is up to. ## Requirements 1. Form a clear picture of the project requirements. Spend some time reading through: - This readme doc. - - The [Slack Web API docs](https://api.slack.com/web) and [Basic message formatting guidelines](https://api.slack.com/docs/message-formatting). - - The code that has been provided in the `SlackBot` project -- particulary the Slack.java class, which provides methods that your bot can use to interact with Slack's Web API. + - The [Slack Web API docs](https://api.slack.com/web) and + [Basic message formatting guidelines](https://api.slack.com/docs/message-formatting). + - The code that has been provided in the `SlackBot` project -- particulary the Slack.java class, + which provides methods that your bot can use to interact with Slack's Web API. - Use the IntelliJ TODO panel (⌘6) to navigate to each of the project TODOs. -2. For both of the following Slack API JSON objects, write a Java class to parse and represent it as a Java object. Each team member should be responsible for parsing at least one of the classes: +2. For both of the following Slack API JSON objects, write a Java class to parse and represent it as a Java object. + Each team member should be responsible for parsing at least one of the classes: - [user](https://api.slack.com/types/user) -> User.java - [attachment](https://api.slack.com/docs/message-attachments) -> Attachment.java - Attachment.java and User.java files are already provided in the `model` subpackage -- just complete the TODOs as marked. See the Channel.java class for an example of how your completed classes should look. + Attachment.java and User.java files are already provided in the `model` subpackage -- just complete the TODOs + as marked. See the Channel.java class for an example of how your completed classes should look. -3. In Bot.java, design and implement your bot code! It's up to your team to decide what your bot does, but at a minimum, when your program runs it should post a message with some content to the #bots channel. See below for some ideas. +3. In Bot.java, design and implement your bot code! It's up to your team to decide what your bot does, but at +a minimum, when your program runs it should post a message with some content to the #bots channel. See below +for some ideas. -4. (Optional / Bonus!) In `Slack.java`, implement the `sendMessageWithAttachments(String messageText, List attachments)`, which should take in a `String messageText` and a `List attachments` to post to the #bots channel. It should return a `SendMessageResponse`. If your bot will send messages with attachments, you must implement this method. Read https://api.slack.com/docs/message-attachments to familiarize yourself with how attachment URL parameters should be formatted. +4. (Optional / Bonus!) In `Slack.java`, implement the `sendMessageWithAttachments(String messageText, + List attachments)`, which should take in a `String messageText` and a `List + attachments` to post to the #bots channel. It should return a `SendMessageResponse`. If your bot will + send messages with attachments, you must implement this method. + Read https://api.slack.com/docs/message-attachments to familiarize yourself with how attachment URL + parameters should be formatted. 5. Respect the **bot etiquette guidelines**: - - Bots may only post messages to the #bots channel! No direct messages or posting to pre-existing channels like #general or #random. + - Bots may only post messages to the #bots channel! No direct messages or posting to pre-existing channels + like #general or #random. - No spamming or flooding the channel with messages: bots should post at most one or two messages at a time. - Keep it classroom friendly :) ## Some bot ideas -- Pig Latin Bot: looks at the text of the last message that was posted to the channel and re-posts it in [pig latin](https://en.wikipedia.org/wiki/Pig_Latin) (or rot13!). +- Pig Latin Bot: looks at the text of the last message that was posted to the channel and re-posts it in [ + pig latin](https://en.wikipedia.org/wiki/Pig_Latin) (or rot13!). - Random Fact Bot: post a random fact or programming tip from a curated list. - Inspirational Image Bot: post a random image link from a selected list of favorite image URLs. - Mashup Bot: get and post interesting content from [another API](https://gist.github.com/afeld/4952991). @@ -54,7 +86,10 @@ The following setup steps only need to be completed **once per team**: ## Take 15 minutes to discuss the following questions: - What will your bot do? What messages will it post? Be specific! -- Draw out a rough blueprint for how you will achieve this programmatically -- it's ok if you don't know all the specifics yet, just sketch out some ideas for how your program might flow. Think about: If your bot is posting data (i.e. images, quotes, facts), where is the data coming from? How is your bot interacting with and responding to other messages / users on the channel? For example: +- Draw out a rough blueprint for how you will achieve this programmatically -- +it's ok if you don't know all the specifics yet, just sketch out some ideas for how your program might flow. +Think about: If your bot is posting data (i.e. images, quotes, facts), where is the data coming from? +How is your bot interacting with and responding to other messages / users on the channel? For example: >Cat Bot: The program will have an ArrayList of URLs of cat images that we find on the internet. When it starts, the program will check the last 100 messages on the #bots channel using the `listMessages()` method. If there is a message that contains the word "cat" in its text, the program with post a message with the text "CAT!!!" and a link to one of our cat image URLs. - How will your team divide tasks? @@ -67,6 +102,9 @@ The following setup steps only need to be completed **once per team**: ## Submission -1. For each feature that you work on, create a new branch in your forked SlackBot repo named `XXMMDD_FeatureName`, where `XXMMDD` are your initials and the month and day and `FeatureName` describes the feature you are working on. When you finish each feature, add, commit and push your changes. On GitHub, open a new Pull Request and assign it to your teammate to review and merge. +1. For each feature that you work on, create a new branch in your forked SlackBot repo named +`XXMMDD_FeatureName`, where `XXMMDD` are your initials and the month and day and `FeatureName` +describes the feature you are working on. When you finish each feature, add, commit and push your changes. +On GitHub, open a new Pull Request and assign it to your teammate to review and merge. 2. This assignment is due by ***9pm on Saturday 9/18***. All code should be committed and pushed by the deadline. Each team member should complete the Google Form (check Slack!) to submit. diff --git a/src/nyc/c4q/ramonaharrison/Bot.java b/src/nyc/c4q/ramonaharrison/Bot.java index 6a52dd4..e7ae70b 100644 --- a/src/nyc/c4q/ramonaharrison/Bot.java +++ b/src/nyc/c4q/ramonaharrison/Bot.java @@ -75,6 +75,7 @@ public void listMessages(String channelId) { * @param text message text. */ public void sendMessageToBotsChannel(String text) { + SendMessageResponse sendMessageResponse = Slack.sendMessage(text); if (sendMessageResponse.isOk()) { diff --git a/src/nyc/c4q/ramonaharrison/Main.java b/src/nyc/c4q/ramonaharrison/Main.java index 933e92b..bf1806c 100644 --- a/src/nyc/c4q/ramonaharrison/Main.java +++ b/src/nyc/c4q/ramonaharrison/Main.java @@ -8,17 +8,15 @@ public static void main(String[] args) { Bot myBot = new Bot(); - myBot.testApi(); + //myBot.testApi(); + // myBot.listChannels(); + // myBot.listMessages(Slack.BOTS_CHANNEL_ID); - myBot.listChannels(); +// Post "Hello, world!" to the #bots channel + myBot.sendMessageToBotsChannel(" "); - myBot.listMessages(Slack.BOTS_CHANNEL_ID); - - // Post "Hello, world!" to the #bots channel - //myBot.sendMessage("Hello, world!"); - - // Post a pineapple photo to the #bots channel - //myBot.sendMessage("http://weknowyourdreams.com/images/pineapple/pineapple-07.jpg"); +// Post a pineapple photo to the #bots channel + //myBot.sendMessage("http://weknowyourdreams.com/images/pineapple/pineapple-07.jpg"); } } \ No newline at end of file diff --git a/src/nyc/c4q/ramonaharrison/model/Attachment.java b/src/nyc/c4q/ramonaharrison/model/Attachment.java index 8b9d1ef..dcefecc 100644 --- a/src/nyc/c4q/ramonaharrison/model/Attachment.java +++ b/src/nyc/c4q/ramonaharrison/model/Attachment.java @@ -1,7 +1,12 @@ package nyc.c4q.ramonaharrison.model; +import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + /** * Created by Ramona Harrison * on 8/26/16 @@ -13,27 +18,139 @@ public class Attachment { - // TODO: implement private fields for each of the following attachment JSON keys: - // "fallback" - // "color" - // "pretext" - // "author_name" - // "author_link" - // "author_icon" - // "title" - // "title_link" - // "text" - // "fields" - // "image_url" - // "thumb_url" - // "footer" - // "footer_icon" - // "ts" + + private String fallback; + private String color; + private String pretext; + private String authorName; + private String authorLink; + private String authorIcon; + private String title; + private String titleLink ; + private String text; + private Listfields; + private String imageUrl; + private String thumbUrl; + private String footer; + private String footerIcon; + private long ts; public Attachment(JSONObject json) { - // TODO: parse an attachment from the incoming json + + if (json.containsKey("fallback")){ + this.fallback = (String)json.get("fallback"); + } + + if (json.containsKey("color")){ + this.color = (String)json.get("color"); + } + if (json.containsKey("pretext")){ + this.pretext = (String)json.get("pretext"); + } + if (json.containsKey("author_name")){ + this.authorName = (String)json.get("author_name"); + } + if (json.containsKey("author_link")){ + this.authorLink = (String)json.get("author_link"); + } + if (json.containsKey("author_icon")){ + this.authorIcon = (String)json.get("author_icon"); + } + if (json.containsKey("title")){ + this.title = (String)json.get("title"); + } + if (json.containsKey("title_link")){ + this.titleLink = (String)json.get("title_link"); + } + if (json.containsKey("text")){ + this.text = (String)json.get("text"); + } + if (json.containsKey("image_url")){ + this.imageUrl = (String)json.get("image_url"); + } + if (json.containsKey("thumb_url")){ + this.thumbUrl = (String)json.get("thumb_url"); + } + if (json.containsKey("footer")){ + this.footer = (String)json.get("footer"); + } + if (json.containsKey("footer_icon")){ + this.footerIcon = (String)json.get("footer_icon"); + } + + if (json.containsKey("fields")){ + JSONArray jsonFields = (JSONArray) json.get("fields"); + this.fields = new ArrayList(); + + for (int i = 0; i getFields() { + return fields; + } + public String getImageUrl() { + return imageUrl; + } + + public String getThumbUrl() { + return thumbUrl; + } + + public String getFooter() { + return footer; + } + + public String getFooterIcon() { + return footerIcon; + } + + public long getTs() { + return ts; + } } diff --git a/src/nyc/c4q/ramonaharrison/model/Fields.java b/src/nyc/c4q/ramonaharrison/model/Fields.java new file mode 100644 index 0000000..1c2d62b --- /dev/null +++ b/src/nyc/c4q/ramonaharrison/model/Fields.java @@ -0,0 +1,38 @@ +package nyc.c4q.ramonaharrison.model; + +import org.json.simple.JSONObject; + +/** + * Created by meltemyildirim on 9/11/16. + */ +public class Fields { + private String title; + private String value; + private boolean isShort; + + public Fields(JSONObject json){ + if (json.containsKey("title")){ + this.title = (String) json.get("title"); + } + + if (json.containsKey("value")) { + this.value = (String) json.get("value"); + } + + if (json.containsKey("short")){ + this.isShort =(boolean) json.get("short"); + } + } + + public String getTitle() { + return title; + } + + public String getValue() { + return value; + } + + public boolean isShort() { + return isShort; + } +} diff --git a/src/nyc/c4q/ramonaharrison/model/Message.java b/src/nyc/c4q/ramonaharrison/model/Message.java index 8ea24bd..12b8028 100644 --- a/src/nyc/c4q/ramonaharrison/model/Message.java +++ b/src/nyc/c4q/ramonaharrison/model/Message.java @@ -30,7 +30,7 @@ public class Message { - private String text; + private String text ; private String ts; private String user; List attachments; diff --git a/src/nyc/c4q/ramonaharrison/model/Profile.java b/src/nyc/c4q/ramonaharrison/model/Profile.java new file mode 100644 index 0000000..a8b7296 --- /dev/null +++ b/src/nyc/c4q/ramonaharrison/model/Profile.java @@ -0,0 +1,117 @@ +package nyc.c4q.ramonaharrison.model; + +import org.json.simple.JSONObject; + +/** + * Created by meltemyildirim on 9/11/16. + */ + +public class Profile { + private String firstName; + private String lastName; + private String realName; + private String email ; + private String skype; + private String phone; + private String image24; + private String image32; + private String image48; + private String image72; + private String image192; + private String image512; + + public Profile(JSONObject json)throws Exception{ + + if (json.containsKey("first_name")){ + this.firstName = (String)json.get("first_name"); + } + if (json.containsKey("last_name")){ + this.lastName = (String)json.get("last_name"); + } + + if (json.containsKey("real_name")){ + this.realName = (String)json.get("real-name"); + } + + if (json.containsKey("email")){ + this.email = (String)json.get("email"); + } + + if (json.containsKey("skype")){ + this.skype = (String)json.get("skype"); + } + + if (json.containsKey("phone")){ + this.phone = (String)json.get("phone"); + } + if (json.containsKey("image_24")){ + this.image24 = (String)json.get("image_24"); + } + if (json.containsKey("image_32")){ + this.image32 = (String)json.get("image_32"); + } + if (json.containsKey("image_48")){ + this.image48 = (String)json.get("image_48"); + } + + if (json.containsKey("image_72")){ + this.image72 = (String)json.get("image_72"); + } + if (json.containsKey("image_192")){ + this.image192 = (String)json.get("image_192"); + } + if (json.containsKey("image_512")){ + this.image512 = (String)json.get("image_512"); + } + + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public String getRealName() { + return realName; + } + + public String getEmail() { + return email; + } + + public String getSkype() { + return skype; + } + + public String getPhone() { + return phone; + } + + public String getImage_24() { + return image24; + } + + public String getImage_32() { + return image32; + } + + public String getImage_48() { + return image48; + } + + public String getImage_72() { + return image72; + } + + public String getImage_192() { + return image192; + } + + public String getImage_512() { + return image512; + } +} + diff --git a/src/nyc/c4q/ramonaharrison/model/User.java b/src/nyc/c4q/ramonaharrison/model/User.java index bc309eb..0f6e630 100644 --- a/src/nyc/c4q/ramonaharrison/model/User.java +++ b/src/nyc/c4q/ramonaharrison/model/User.java @@ -13,24 +13,116 @@ public class User { - // TODO: implement private fields for each of the following user JSON keys: - // "id" - // "name" - // "deleted" - // "color" - // "profile" - // "is_admin" - // "is_owner" - // "is_primary_owner" - // "is_restricted" - // "is_ultra_restricted" - // "has_2fa" - // "two_factor_type" - // "has_files" + + private int id; + private String name; + private boolean deleted; + private String color; + private Profile profile; + private boolean isAdmin; + private boolean isOwner; + private boolean isPrimaryOwner; + private boolean isRestricted; + private boolean isUltraRestricted; + private boolean has2fa; + private String twoFactorType; + private boolean hasFiles; public User(JSONObject json) { - // TODO: parse a user from the incoming json + if (json.containsKey("id")) { + this.id = (Integer) json.get("id"); + } + if (json.containsKey("deleted")) { + this.deleted = (boolean) json.get("deleted"); + } + if (json.containsKey("color")) { + this.color = (String) json.get("color"); + } + if (json.containsKey("profile")) { + this.profile = (Profile) json.get("profile"); + } + if (json.containsKey("isAdmin")) { + this.isAdmin = (boolean) json.get("name"); + } + if (json.containsKey("isOwner")) { + this.isOwner = (boolean) json.get("isOwner"); + } + if (json.containsKey("isPrimaryOwner")) { + this.isPrimaryOwner = (boolean) json.get("isPrimaryOwner"); + } + if (json.containsKey("isRestricted")) { + this.isRestricted = (boolean) json.get("isRestricted"); + } + if (json.containsKey("isUltraRestricted")) { + this.isUltraRestricted= (boolean) json.get("isUltraRestricted"); + } + if (json.containsKey("has2fa")) { + this.has2fa = (boolean) json.get("has2fa"); + } + if (json.containsKey("twoFactorType")) { + this.twoFactorType = (String) json.get("twoFactorType"); + } + if (json.containsKey("hasFiles")) { + this.hasFiles = (boolean) json.get("hasFiles"); + } + if (json.containsKey("name")) { + this.name = (String) json.get("name"); + } + } + + + + + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public boolean isDeleted() { + return deleted; + } + + public String getColor() { + return color; + } + + public Profile getProfile() { + return this.profile; } - // TODO add getters to access private fields + public boolean isAdmin() { + return isAdmin; + } + + public boolean isOwner() { + return isOwner; + } + + public boolean isPrimaryOwner() { + return isPrimaryOwner; + } + + public boolean isRestricted() { + return isRestricted; + } + + public boolean isUltraRestricted() { + return isUltraRestricted; + } + + public boolean isHas2fa() { + return has2fa; + } + + public String getTwoFactorType() { + return twoFactorType; + } + + public boolean isHasFiles() { + return hasFiles; + } } diff --git a/src/nyc/c4q/ramonaharrison/network/Slack.java b/src/nyc/c4q/ramonaharrison/network/Slack.java index 87521bd..98b1ca9 100644 --- a/src/nyc/c4q/ramonaharrison/network/Slack.java +++ b/src/nyc/c4q/ramonaharrison/network/Slack.java @@ -28,7 +28,7 @@ public class Slack { private static final String ENDPOINT_POST_MESSAGE = "chat.postMessage"; private static final String ENDPOINT_DELETE_MESSAGE = "chat.delete"; - public static final String BOTS_CHANNEL_ID = "C2ABKERFT"; + public static final String BOTS_CHANNEL_ID = "C2ADPS5MK"; /** * Static method to test the Slack API. diff --git a/src/nyc/c4q/ramonaharrison/util/Token.java b/src/nyc/c4q/ramonaharrison/util/Token.java index 3f0c788..9519686 100644 --- a/src/nyc/c4q/ramonaharrison/util/Token.java +++ b/src/nyc/c4q/ramonaharrison/util/Token.java @@ -15,7 +15,7 @@ public class Token { public static String findApiToken() { - String apiKey = ""; + String apiKey = "067574bc9c32812a423cdd46ade04e4e-us14"; File file = new File("api_token.txt"); System.out.println(file.getAbsolutePath());