Hi all, our Mobile team at TripAdvisor started using HipChat mid last year for internal dev communication and it turned out to be a brilliant idea. It has simply changed the way we communicate, we no longer have to wait for other teams across the coast or continent to see an email and respond. 1-on-1 private chats/notifications prompt faster responses from fellow developers. In this post, I'm going to explain a hacky bridge that I built between XMPP based hubot and HipChat v2 API that allows one to send rich HTML messages to HipChat via hubot.
Table of Contents
- Setting it up
- Hubot Script Structure and Message Payload
- Generating HipChat Room's XMPP JID to API ID mapping
- Reviewboard Hubot Script
- Putting it all together
- Related articles on the web
We maintain a HipChat Bot named hbot powered by hubot for various automation/querying tasks. At the start of this year, there was a rising demand for pretty responses using rich HTML format compared to a stream of text separated by newlines. I'm completely fine with reading a stream of text but it turns out that the rest of the world isn't (including Igor Nikolaev, Justin Leider and Ryne McCall). Hence, I needed to figure out a way to send HTML messages via hubot.
Like any sane human being, you'd think this would be easy peasy. Turns out you are wrong because of hubot gitlab issue #151. This leads you to Support XHTML-IM spec in HipChat (XMPP). The latest update (as of April 2015) on the previous link states that it's something that they would support sometime in the future. Presently HipChat allows XHTML-IM body via HipChat v2 API.
For a while, I was at a dilemma about bridging the two protocols (XMPP and HipChat API) as I knew that I would be implementing a horrible hack to make this work. Truth be told, I shouldn't even be writing this tech post and let HipChat fix it for real. I know that I'll regret this hack sometime in the future but that's a thought for another day, so without further ado, let me explain to you how you can send rich html messages to HipChat from hubot.
I will not delve deep into this section, since I assume that you already have a working hipchat and hubot instance. However, in the interest of general public, I will list out some pointers below for setting up hubot.
Any hubot script structure will look something like below.
In a normal scenario, you'd send the message back using msg.send, however, in our case, we need to use the HipChat v2 API to send the message back. In order to do so, we need the HipChat Room API ID from which we received the message from. Let's examine meta data present in msg.
The only useful Room ID that we can work with is the Room JID that is accessible via msg.message.user.reply_to.
As per the send_room_notification API docs, we need the API Room ID to post a room notification. As shown in the JSON payload previously, we don't have the API Room ID available via hubot but we do have the XMPP JID via reply_to. Hence we need to generate the mapping from XMPP JID to API ID. The necessary steps to do so are listed below.
You can grab your account's all powerful access token at https://www.hipchat.com/account/api OR https://YOUR_HIPCHAT_INSTANCE/account/api. The auth token will be similar to a SHA-1 hash such as eacb0d1b53a6f12893e95c7c5aec16de3ff2a939. This is your auth_token that can be used with HipChat v2 API.
Refer to get_all_rooms API docs in order to dump the list of Rooms. You can dump the list of rooms via below curl command or the python script (useful template for paging when you have greater than 1000 rooms).
The JSON output in rooms.json will be as below. The API Room ID field is what we care about the most.
We can extract the XMPP JID via API ID using get_room API endpoint. For example, if we have a Room with API ID 100, the get_room API call returns the following response.
The following script can be used to dump a CSV file of XMPP JID and API ID while adhering to HipChat API Rate Limits.
In order to demonstrate posting html messages to hipchat, I will use the reviewboard example. Whenever someone on our team needs "Ship It's", they post a short hand notation "!rb REVIEW_ID" in the relevant hipchat room and it is hbot's responsibility to pull out relevant details of the reviewboard entry in question and display it in the room as shown in the below screenshot.
I have already outlined the Hubot-Script-Structure, however, we need to do some preprocessing to post HTML messages. I have broken the full hubot script into sections and described each one of them below.
The following code describes the hubot review board script and it's dependencies. I have intentionally left out Reviewboard authentication config variables and assume that the reader is familiar with it, see reviewboard web API guide for the details. Also, for the sake of simplicity, I will assume a function that will return the correct reviewboard JSON response.
The following code loads the xmpp_jid_api_id_map.csv file to a coffescript map/object where the key is xmpp_jid and the value is api_id. Please note that the mapping file should be placed in hubot's root folder.
The following code sets up a Handlebars template that is used to generate the HTML from the reviewboard json object.
The following code listens to the reviewboard regex (!rb REVIEW_ID) and tries to fetch the reviewboard entry details. It posts a HipChat Notification if we have xmpp_jid to api_id mapping, else it sends a raw string message back.
The following code block posts a hipchat room notification by making a POST request to send_room_notification endpoint with necessary auth credentials and POST data. getNotificationPayload function returns the JSON payload consisting of message, message_format and color. errorHandler function is called when we fail to post a room notification.
The full hubot script is basically a concatenation of each of the sections described above and can be found at https://github.com/ravikiranj/hipchat/blob/master/rb.coffee.
- If a new hipchat room was created after you generated the XMPP_JID to API_ID mapping, it will receive the raw string version of the response and not the pretty HTML format. To fix this, simply add the new hipchat room mapping by looking it up in the web UI (needs admin access) or make API calls to find out.
- You will need to routinely regenerate the XMPP_JID to API_ID mapping to keep it in sync with the current list of hipchat rooms.