ac-node-hipchat
Version:
A common module plugin for building Atlassian Connect add-ons for HipChat
403 lines (350 loc) • 11.5 kB
JavaScript
var rsvp = require('rsvp');
var Promise = rsvp.Promise;
var request = require('request');
var check = require('check-types');
var verify = check.verify;
var TenantClient = require('./tenant-client');
var defaultScopes = ['send_notification'];
function RestClient(httpClient) {
this._httpClient = httpClient;
}
RestClient.prototype._request = function (options) {
var self = this;
return new Promise(function (resolve, reject) {
var method = (options.method || 'GET').toUpperCase();
self._httpClient({
uri: options.uri || options.url,
method: method,
qs: options.qs,
body: options.body,
json: true,
auth: options.auth
}, function (err, response, body) {
if (err) return reject(err);
var status = response.statusCode;
if ((options.expect && status !== options.expect) || status < 200 || status >= 400) {
var msg = 'Unexpected response code ' + status + ': ' + method + ' ' + options.url;
if (body && body.error && body.error.message) {
msg += ': ' + body.error.message;
}
err = new Error(msg);
err.response = response;
err.body = body;
return reject(err);
}
resolve({
status: response.statusCode,
raw: response,
body: body
});
});
});
};
RestClient.prototype._get = function (resourceUrl, token, options) {
verify.webUrl(resourceUrl);
verify.string(token);
verify.maybe.object(options);
options = options || {};
var qs = exports.optionsToQs(options);
return this._request({
url: resourceUrl,
method: 'GET',
expect: 200,
qs: qs,
auth: {bearer: token}
}).then(function (response) {
return response.body;
});
};
RestClient.prototype._post = function (resourceUrl, token, options, expect, body) {
verify.webUrl(resourceUrl);
verify.string(token);
verify.maybe.object(options);
options = options || {};
return this._request({
url: resourceUrl,
method: 'POST',
expect: expect,
auth: {bearer: token},
body: body
}).then(function (response) {
return expect === 200 || expect === 201 ? response.body : null;
});
};
RestClient.prototype._put = function (resourceUrl, token, options, expect, body) {
verify.webUrl(resourceUrl);
verify.string(token);
verify.maybe.object(options);
options = options || {};
return this._request({
url: resourceUrl,
method: 'PUT',
expect: expect,
auth: {bearer: token},
body: body
}).then(function (response) {
return expect === 200 || expect === 201 ? response.body : null;
});
};
RestClient.prototype._del = function (resourceUrl, token) {
verify.webUrl(resourceUrl);
verify.string(token);
return this._request({
url: resourceUrl,
method: 'DELETE',
expect: 204,
auth: {bearer: token}
}).then(function (response) {
return null;
});
};
RestClient.prototype.getCapabilities = function (resourceUrl) {
return this._request({
url: resourceUrl,
expect: 200
}).then(function (response) {
return response.body;
});
};
RestClient.prototype.getEmoticons = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getEmoticon = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.deleteSession = function (resourceUrl, token) {
return this._del(resourceUrl, token);
};
RestClient.prototype.generateToken = function (resourceUrl, username, password, scopes) {
verify.string(username);
verify.string(password);
scopes = scopes || defaultScopes;
return this._request({
url: resourceUrl,
method: 'POST',
expect: 200,
auth: {
username: username,
password: password
},
body: {
grant_type: 'client_credentials',
scope: scopes.join(' ')
}
}).then(function (response) {
return response.body;
});
};
RestClient.prototype.getSession = function (resourceUrl, token) {
return this._get(resourceUrl, token);
};
RestClient.prototype.getRoomMessage = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
// TODO: share file with room
RestClient.prototype.createRoom = function (resourceUrl, token, room) {
verify.object(room);
room = exports.camelsToSnakes(room);
check.map(room, {
name: verify.string,
topic: verify.string,
guest_access: verify.maybe.boolean,
owner_user_id: verify.defined,
privacy: verify.maybe.string
});
return this._post(resourceUrl, token, null, 201, room);
};
RestClient.prototype.getRooms = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getRecentRoomHistory = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.sendNotification = function (resourceUrl, token, message, options) {
verify.string(message);
options = options || {};
return this._post(resourceUrl, token, options, 204, {
message: message,
from: options.from,
color: options.color || 'yellow',
notify: options.notify === true ? options.notify : false,
message_format: options.format || 'html',
card: options.card
});
};
RestClient.prototype.updateRoom = function (resourceUrl, token, room) {
verify.object(room);
room = exports.camelsToSnakes(room);
check.map(room, {
name: verify.string,
privacy: verify.string,
is_archived: verify.boolean,
is_guest_accessible: verify.boolean,
topic: verify.string,
owner: {
id: verify.defined
}
});
return this._put(resourceUrl, token, null, 204, room);
};
RestClient.prototype.getRoom = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.deleteRoom = function (resourceUrl, token) {
return this._del(resourceUrl, token);
};
RestClient.prototype.createRoomWebhook = RestClient.prototype.createWebhook = function (resourceUrl, token, webhook) {
verify.object(webhook);
webhook = exports.camelsToSnakes(webhook);
check.map(webhook, {
event: verify.pattern,
name: verify.string,
url: verify.webUrl,
pattern: verify.maybe.string
});
return this._post(resourceUrl, token, null, 201, webhook);
};
RestClient.prototype.getRoomWebhooks = RestClient.prototype.getWebhooks = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getRoomStatistics = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.replyToMessage = function (resourceUrl, token, parentMessageId, message) {
verify.string(parentMessageId);
verify.string(message);
return this._post(resourceUrl, token, null, 204, {
parentMessageId: parentMessageId,
message: message
});
};
RestClient.prototype.getRoomMembers = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.setRoomTopic = function (resourceUrl, token, topic) {
verify.string(topic);
return this._put(resourceUrl, token, null, 204, {
topic: topic
});
};
RestClient.prototype.shareLinkWithRoom = function (resourceUrl, token, link, message) {
verify.string(link);
verify.maybe.string(message);
return this._put(resourceUrl, token, null, 204, {
link: link,
message: message
});
};
RestClient.prototype.addRoomMember = function (resourceUrl, token) {
return this._put(resourceUrl, token, null, 204);
};
RestClient.prototype.removeRoomMember = function (resourceUrl, token) {
return this._del(resourceUrl, token);
};
RestClient.prototype.deleteRoomWebhook = RestClient.prototype.deleteWebhook = function (resourceUrl, token) {
return this._del(resourceUrl, token);
};
RestClient.prototype.getRoomWebhook = RestClient.prototype.getWebhook = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getRoomHistory = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getPrivateChatMessage = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getRecentPrivateChatHistory = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.updateUserPhoto = function (resourceUrl, token, photo) {
verify.string(photo);
return this._put(resourceUrl, token, null, 204, {
photo: photo
});
};
RestClient.prototype.deleteUserPhoto = function (resourceUrl, token) {
return this._del(resourceUrl, token);
};
RestClient.prototype.forTenant = function (tenant, cache, scopes) {
return new TenantClient(this, tenant, cache, scopes);
};
RestClient.prototype.updateUser = function (resourceUrl, token, user) {
verify.object(user);
user = exports.camelsToSnakes(user);
check.map(user, {
name: verify.string,
title: verify.maybe.string,
presence: verify.maybe.object,
mention_name: verify.maybe.string,
is_group_admin: verify.maybe.boolean,
timezone: verify.maybe.string,
password: verify.maybe.string,
email: verify.string
});
return this._put(resourceUrl, token, null, 204, user);
};
RestClient.prototype.deleteUser = function (resourceUrl, token) {
return this._del(resourceUrl, token);
};
RestClient.prototype.getUser = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.getUsers = function (resourceUrl, token, options) {
return this._get(resourceUrl, token, options);
};
RestClient.prototype.glancePushUser = function (resourceUrl, token, data) {
return this._post(resourceUrl, token, null, 204, data);
};
RestClient.prototype.glancePushRoom = function (resourceUrl, token, data) {
return this._post(resourceUrl, token, null, 204, data);
};
RestClient.prototype.glancePushGroup = function (resourceUrl, token, data) {
return this._post(resourceUrl, token, null, 204, data);
};
RestClient.prototype.createUser = function (resourceUrl, token, user) {
verify.object(user);
user = exports.camelsToSnakes(user);
check.map(user, {
name: verify.string,
title: verify.maybe.string,
mention_name: verify.maybe.string,
is_group_admin: verify.maybe.boolean,
timezone: verify.maybe.string,
password: verify.maybe.string,
email: verify.string
});
return this._post(resourceUrl, token, null, 201, user);
};
RestClient.prototype.shareLinkWithUser = function (resourceUrl, token, link, message) {
verify.string(link);
verify.maybe.string(message);
return this._put(resourceUrl, token, null, 204, {
link: link,
message: message
});
};
// TODO: share file with user
exports.optionsToQs = function (options) {
var qs = {};
Object.keys(options).forEach(function (key) {
var dashKey = key.replace(/[A-Z]/g, function ($0) {
return '-' + $0.toLowerCase();
});
qs[dashKey] = options[key];
});
return qs;
};
exports.camelsToSnakes = function (camels) {
var snakes = {};
Object.keys(camels).forEach(function (key) {
var snakeKey = key.replace(/[A-Z]/g, function ($0) {
return '_' + $0.toLowerCase();
});
snakes[snakeKey] = camels[key];
// TODO: recurse objects and arrays?
});
return snakes;
};
module.exports = function (httpClient) {
return new RestClient(httpClient || request);
};