1 | # atlassian-connect-express-hipchat: Node.js module for Express based HipChat Connect Add-ons
|
2 |
|
3 | [![Build Status](https://drone.io/bitbucket.org/hipchat/atlassian-connect-express-hipchat/status.png)](https://drone.io/bitbucket.org/hipchat/atlassian-connect-express-hipchat/latest)
|
4 |
|
5 | `atlassian-connect-express-hipchat` is an NPM module for creating [HipChat Connect](https://www.hipchat.com/docs/apiv2/addons) Add-ons with [Node.js](http://nodejs.org/). HipChat Connect is a variant of [Atlassian Connect](https://developer.atlassian.com/static/connect/docs/) and `atlassian-connect-express-hipchat` is a HipChat compatibility layer on top of [atlassian-connect-express](https://bitbucket.org/atlassian/atlassian-connect-express) (aka, ACE).
|
6 |
|
7 | ## More about `atlassian-connect-express-hipchat`
|
8 |
|
9 | The `atlassian-connect-express-hipchat` package helps you get started developing add-ons quickly, using Node.js and Express as the add-on server.
|
10 |
|
11 | It's important to understand that [Express](http://expressjs.com/) by itself is a web app framework for Node. `atlassian-connect-express-hipchat` just provides a library of middleware and convenience helpers that make it easier to build HipChat add-ons. Specifically, `atlassian-connect-express-hipchat` adds:
|
12 |
|
13 | * Automatic JWT authentication of inbound requests
|
14 | * Automatic persistence of host details (i.e., client information)
|
15 | * HipChat client for communicating with the HipChat REST API
|
16 |
|
17 | ## Getting Started
|
18 |
|
19 | The fastest way to get started is to install the `atlas-connect` CLI tool. The CLI makes it possible to generate a `atlassian-connect-express-hipchat` enabled add-on scaffold very quickly. To install:
|
20 |
|
21 | npm i -g atlas-connect
|
22 |
|
23 | ### Create a project
|
24 |
|
25 | Let's start by creating an add-on project:
|
26 |
|
27 | atlas-connect new -t hipchat <project_name>
|
28 |
|
29 | This creates a new project home directory with the following contents:
|
30 |
|
31 | .
|
32 | ├── Procfile
|
33 | ├── README.md
|
34 | ├── app.js
|
35 | ├── atlassian-connect.json
|
36 | ├── config.json
|
37 | ├── lib
|
38 | │ └── hipchat.js
|
39 | ├── package.json
|
40 | ├── public
|
41 | │ ├── css
|
42 | │ │ └── addon.css
|
43 | │ └── js
|
44 | │ └── addon.js
|
45 | ├── routes
|
46 | │ └── index.js
|
47 | └── views
|
48 | ├── config.hbs
|
49 | └── layout.hbs
|
50 |
|
51 | ### Install dependencies
|
52 |
|
53 | Change to the new project directory and install dependencies:
|
54 |
|
55 | npm install
|
56 |
|
57 | ### Setting up a development environment
|
58 |
|
59 | The development workflow for building HipChat add-ons is rad. You can build your add-on locally while running it inside of <https://hipchat.com>. To do this, you'll need to expose your local webserver to the internet. An easy way to do this is to use a [local tunnel](http://en.wikipedia.org/wiki/Tunneling_protocol). We highly recommend using [ngrok](https://ngrok.com/). `ngrok` is a simple client tool that allows you to forward internet requests on an ngrok subdomain to your local server:
|
60 |
|
61 | ngrok -subdomain <subdomain-name> <port>
|
62 |
|
63 | ### Running your Add-on Server
|
64 |
|
65 | Once you've started your tunnel, you can run your add-on server:
|
66 |
|
67 | AC_LOCAL_BASE_URL=https://<subdomain>.ngrok.com node app.js
|
68 |
|
69 | This will boot up your add-on server on the default port of 3000. The `AC_LOCAL_BASE_URL` environment variable tells your add-on to use the specified base URL instead of <http://localhost:3000>.
|
70 |
|
71 | ### The Dev Loop
|
72 |
|
73 | At this point, you can start building your add-on. Changes to views load automatically, however, if you make changes to any JavaScript, you need to restart your add-on server. If you want your server to automatically restart when your JavaScript changes, consider using [nodemon](https://npmjs.org/package/nodemon).
|
74 |
|
75 | AC_LOCAL_BASE_URL=https://<subdomain>.ngrok.com nodemon app.js
|
76 |
|
77 | ### Registering your Add-on with HipChat
|
78 |
|
79 | To get your add-on into HipChat, you have to register your addon's `atlassian-connect.json` descriptor. This descriptor will be accessible through:
|
80 |
|
81 | https://<subdomain>.ngrok.com/atlassian-connect.json
|
82 |
|
83 | HipChat add-ons can operate inside a room or within the entire account. When developing, you should probably register your add-on inside a room you've created just for testing. Also, you can only register add-ons inside a room where you are an administrator.
|
84 |
|
85 | To register your add-on descriptor, navigate to the rooms administration page:
|
86 |
|
87 | https://<your-account>.hipchat.com/rooms
|
88 |
|
89 | Then select one of your rooms in the list. In the following page, select `Add-ons` in the sidebar:
|
90 |
|
91 | ![Add-on administration](http://f.cl.ly/items/1w2S2z2c3g0k031x3S1d/HipChat%20-%20HipChat%20Add-ons%202014-02-11%2010-32-48.png)
|
92 |
|
93 | Below the page, you'll find the **Create new private add-ons** form. Paste your descriptor URL in the **Capabilities URL** field then save. This will initiate the installation of your add-on inside the room.
|
94 |
|
95 | ### Configuration
|
96 |
|
97 | The configuration for your add-on is done in two files:
|
98 |
|
99 | * `./config.json` -- This file contains the configuration for each runtime environment your add-on runs in. The file has comments to help you understand available settings.
|
100 | * `./atlassian-connect.json` -- This file is a manifest of all the extension points your add-on uses. To see all of the available extension point options, take a look at the [HipChat Add-on Capabilities page](https://www.hipchat.com/docs/apiv2/method/get_capabilities).
|
101 |
|
102 | #### config.json
|
103 |
|
104 | The `./config.json` file contains all of the settings for the add-on server. This file is divided into runtime environments. The default template includes `development` and `production`, but you're free to add any other environments you'd like to use.
|
105 |
|
106 | To run your add-on in a specific environment, use the `NODE_ENV` environment variable:
|
107 |
|
108 | NODE_ENV=<environment> AC_LOCAL_BASE_URL=https://<subdomain>.ngrok.com nodemon app.js
|
109 |
|
110 |
|
111 | ### atlassian-connect.json
|
112 |
|
113 | The `atlassian-connect.json` describes what your add-on will do. There are two main parts to the descriptor: meta information that describes your add-on (i.e., name, description, key, etc.) and a list of the modules your add-on will provide. This descriptor is registered with HipChat when your add-on is installed.
|
114 |
|
115 | To see all of the available settings in the `atlassian-connect.json`, take a look at the [HipChat Add-on Capabilities page](https://www.hipchat.com/docs/apiv2/method/get_capabilities).
|
116 |
|
117 | ## Sample Add-ons using `atlassian-connect-express-hipchat`
|
118 |
|
119 | * [GitHub](https://bitbucket.org/hipchat/hipchat-github-addon) -- get notified of events that happen on GitHub inside your HipChat rooms
|
120 | * [Instagram](https://bitbucket.org/hipchat/hipchat-instagram-addon) -- get room notifications when someone posts a photo matching a tag you're watching
|
121 |
|
122 | ## The `atlassian-connect-express-hipchat` scaffold
|
123 |
|
124 | When you generate a new `atlassian-connect-express-hipchat` add-on, you're actually just downloading a copy of the [Atlassian Connect Expressjs template](https://bitbucket.org/atlassian/atlassian-connect-express-template/src/hipchat/).
|
125 |
|
126 | ### Handlebars layouts and templates
|
127 |
|
128 | The base scaffold uses the [Handlebars](http://handlebarsjs.com) template library via the [express-hbs](https://github.com/barc/express-hbs) package.
|
129 |
|
130 | Handlebars views are stored in the `./views` directory. The base template contains a `layout.hbs` and a configuration page (`config.hbs`). Handlebars alone doesn't provide layouts, but the `express-hbs` package does. To apply the `layout.hbs` layout to your template page, just add the following to the top of your template:
|
131 |
|
132 | {{!< layout}}
|
133 |
|
134 | To learn more about how Handlebars works in Expressjs, take a look at the [express-hbs documentation](https://github.com/barc/express-hbs#readme).
|
135 |
|
136 | ### Special context variables
|
137 |
|
138 | `atlassian-connect-express-hipchat` injects a handful of useful context variables into your render context. You can access any of these within your templates:
|
139 |
|
140 | * `title`: the add-on's name (derived from `atlassian-connect.json`)
|
141 | * `appKey`: the application key defined in `atlassian-connect.json`
|
142 | * `localBaseUrl`: the base URI of the add-on
|
143 | * `hostStylesheetUrl`: the URL to the base CSS file for Connect add-ons. This stylesheet is a bare minimum set of styles to help you get started. It's not a full AUI stylesheet.
|
144 | * `hostScriptUrl`: the URL to the Connect JS client. This JS file contains the code that will establish the seamless iframe bridge between the add-on and its parent. It also contains a handful of methods and objects for accessing data through the parent (look for the `AP` JS object).
|
145 | * `signed_request`: a JWT token that can be used to authenticate calls from the iframe back to the add-on service.
|
146 |
|
147 | You can access any of the variables above as normal Handlebars variables. For example, to generate a link in your page that links elsewhere in the host:
|
148 |
|
149 | <a href="{{hostBaseUrl}}/config">Configuration</a>
|
150 |
|
151 | ## Recipes
|
152 |
|
153 | ### How to secure a route with JWT
|
154 |
|
155 | Add-ons are authenticated through [JWT](http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-15). To simplify JWT verification on your routes, you can simply add a `atlassian-connect-express-hipchat` middleware to your route:
|
156 |
|
157 | module.exports = function (app, addon) {
|
158 | app.get('/protected-resource',
|
159 |
|
160 | // Protect this resource with JWT
|
161 | addon.authenticate(),
|
162 |
|
163 | function(req, res) {
|
164 | res.render('protected');
|
165 | }
|
166 | );
|
167 | };
|
168 |
|
169 | Simply adding the `addon.authenticate()` middleware will protect your resource. It will also make available some useful `request` properties that will be useful in your app:
|
170 |
|
171 | * `req.clientInfo`: useful information about the add-on client such as the clientKey, oauth info, and HipChat account info
|
172 | * `req.context`: contains the context data accompanying the request like the roomId
|
173 |
|
174 | It also populates the `res.signed_request` property that can be used to expose the JWT token to your pages for subsequent requests back to your add-on server.
|
175 |
|
176 | ### How to send a signed HTTP request from the iframe back to the add-on service
|
177 |
|
178 | The initial call to load the iframe content is secured by JWT, as described above. However, the loaded content cannot sign subsequent requests. A typical example is content that makes AJAX calls back to the add-on. Cookie sessions cannot be used, as many browsers block third-party cookies by default. `atlassian-connect-express-hipchat` provides middleware that works without cookies and helps making secure requests from the iframe.
|
179 |
|
180 | A route can be secured by adding the `addon.authenticate()` middleware:
|
181 |
|
182 | module.exports = function (app, addon) {
|
183 | app.get('/protected-resource',
|
184 |
|
185 | // Require a valid token to access this resource
|
186 | addon.authenticate(),
|
187 |
|
188 | function(req, res) {
|
189 | res.render('protected');
|
190 | }
|
191 | );
|
192 | };
|
193 |
|
194 | In order to secure your route, the token must be part of the HTTP request back to the add-on service. This can be done by using a query parameter:
|
195 |
|
196 | <a href="/protected-resource?signed_request={{signed_request}}">See more</a>
|
197 |
|
198 | The second option is to use an HTTP header, e.g. for AJAX requests:
|
199 |
|
200 | beforeSend: function (request) {
|
201 | request.setRequestHeader("X-acpt", {{token}});
|
202 | }
|
203 |
|
204 | You can embed the token anywhere in your iframe content using the `token` content variable. For example, you can embed it in a meta tag, from where it can later be read by a script:
|
205 |
|
206 | <meta name="acpt" content="{{signed_request}}">
|
207 |
|
208 | Both the query parameter `acpt` and the HTTP request header `X-acpt` are automatically recognized and handled by `atlassian-connect-express-hipchat` when a route is secured with the `addon.authenticate()` middleware. The token remains valid for 15 minutes by default, and is automatically refreshed on each call. The expiration of the token can be configured using `maxTokenAge` (in seconds) inside `config.json`.
|
209 |
|
210 | ### How to send a signed outbound HTTP request back to the host
|
211 |
|
212 | `atlassian-connect-express-hipchat` bundles and extends the [request](https://github.com/mikeal/request) HTTP client. To make a request back to the HipChat, all you have to do is use `request` the way it was designed. REST calls back to HipChat require that you use the `access_token` provided to you at installation.
|
213 |
|
214 | To make things easier, we've provided a simple HipChat client for sending messages found inside `./lib/hipchat.js`. To use this, all you have to do is:
|
215 |
|
216 | var hipchat = require('../lib/hipchat')(addon);
|
217 |
|
218 | // This is an example route to handle an incoming webhook
|
219 | app.post('/webhook',
|
220 | addon.authenticate(),
|
221 | function(req, res) {
|
222 | hipchat.sendMessage(req.clientInfo, req.context.item.room.id, 'pong')
|
223 | .then(function(data){
|
224 | res.send(200);
|
225 | });
|
226 | }
|
227 | );
|
228 |
|
229 | ### How to persist data for your add-on
|
230 |
|
231 | `atlassian-connect-express-hipchat` bundles a [Redis](http://redis.io/) [adapter](https://bitbucket.org/atlassianlabs/atlassian-connect-express-redis). *To use Redis with your add-on, you should install Redis locally.*
|
232 |
|
233 | You don't have to use Redis, but the default template makes use of Redis. Redis is awesome for building add-ons, but you're free to use whatever you'd like. We also bundle [JugglingDB](http://jugglingdb.co/) (a cross-database ORM for nodejs) which works with a variety of databases.
|
234 |
|
235 | If you choose to use Redis, congratulations on *doing the right thing*. But more importantly, you might also want to use [redis-commander](https://github.com/joeferner/redis-commander) to manage your Redis data. It's extremely helpful to see what's getting stored in your DB.
|
236 |
|
237 | ### How to deploy to Heroku
|
238 | Before you start, install Git and the [Heroku Toolbelt](https://toolbelt.heroku.com/).
|
239 |
|
240 | If you aren't using git to track your add-on, now is a good time to do so as it is required for Heroku. Ensure you are in your project home directory and run the following commands:
|
241 |
|
242 | git config --global user.name "John Doe"
|
243 | git config --global user.email johndoe@example.com
|
244 | ssh-keygen -t rsa
|
245 | git init
|
246 | git add .
|
247 | git commit . -m "some message"
|
248 | heroku keys:add
|
249 |
|
250 | Next, create the app on Heroku:
|
251 |
|
252 | heroku apps:create <add-on-name>
|
253 |
|
254 | Then set the public and private key as environment variables in Heroku (you don't ever want to commit these `*.pem` files into your scm). The two `.*pem` files were created in your project home directory when you ran the `atlas-connect new` command.
|
255 |
|
256 | heroku config:set AC_LOCAL_BASE_URL=https://<subdomain> herokuapp.com --app <add-on-name>
|
257 | heroku config:set DATABASE_URL=<DB URL> --app <add-on-name>
|
258 |
|
259 | Lastly, let's add the project files to Heroku and deploy!
|
260 |
|
261 | If you aren't already there, switch to your project home directory. From there, run these commands:
|
262 |
|
263 | git remote add heroku git@heroku.com:<add-on-name>.git
|
264 | git push heroku master
|
265 |
|
266 | It will take a minute or two for Heroku to spin up your add-on. When it's done, you'll be given the URL where your add-on is deployed, however, you'll still need to register the `atlassian-connect.json` descriptor on HipChat.
|
267 |
|
268 | For further detail, we recommend reading [Getting Started with Node.js on Heroku](https://devcenter.heroku.com/articles/getting-started-with-nodejs).
|
269 |
|
270 | ## Troubleshooting
|
271 |
|
272 | ### Debugging HTTP Traffic
|
273 |
|
274 | If you're using `ngrok`, you can point your browser to <http://localhost:4040> to access `ngrok`'s built-in traffic analyzer.
|
275 |
|
276 | ## Getting Help or Support
|
277 |
|
278 | You can get help by emailing <atlassian-connect-dev@googlegroups.com> or [report bugs](https://bitbucket.org/hipchat/atlassian-connect-express-hipchat/issues?status=new&status=open). If you want to learn more about HipChat Connect, you can visit <https://www.hipchat.com/docs/apiv2/addons>.
|
279 |
|
280 | ## Contributing
|
281 |
|
282 | Even though this is just an exploratory project at this point, it's also open source [Apache 2.0](https://bitbucket.org/atlassian/atlassian-connect-express-hipchat/src/master/LICENSE.txt). So, please feel free to fork and send us pull requests.
|