UNPKG

19.6 kBJavaScriptView Raw
1"use strict";
2
3// Core packages
4var url = require('url');
5
6// Npm packages
7var request = require('request');
8
9// Custom packages
10var applicationProperties = require('./api/application-properties');
11var attachment = require('./api/attachment');
12var auditing = require('./api/auditing');
13var auth = require('./api/auth');
14var avatar = require('./api/avatar');
15var backlog = require('./api/backlog');
16var board = require('./api/board');
17var comment = require('./api/comment');
18var component = require('./api/component');
19var customFieldOption = require('./api/customFieldOption');
20var dashboard = require('./api/dashboard');
21var epic = require('./api/epic');
22var errorStrings = require('./lib/error');
23var field = require('./api/field');
24var filter = require('./api/filter');
25var group = require('./api/group');
26var groupUserPicker = require('./api/groupUserPicker');
27var groups = require('./api/groups');
28var issue = require('./api/issue');
29var issueLink = require('./api/issueLink');
30var issueLinkType = require('./api/issueLinkType');
31var issueType = require('./api/issueType');
32var jql = require('./api/jql');
33var labels = require('./api/labels');
34var licenseRole = require('./api/licenseRole');
35var licenseValidator = require('./api/licenseValidator');
36var myPermissions = require('./api/myPermissions');
37var myPreferences = require('./api/myPreferences');
38var myself = require('./api/myself');
39var oauth_util = require('./lib/oauth_util');
40var password = require('./api/password');
41var permissions = require('./api/permissions');
42var permissionScheme = require('./api/permission-scheme');
43var priority = require('./api/priority');
44var project = require('./api/project');
45var projectCategory = require('./api/projectCategory');
46var projectValidate = require('./api/projectValidate');
47var reindex = require('./api/reindex');
48var resolution = require('./api/resolution');
49var roles = require('./api/roles');
50var screens = require('./api/screens');
51var search = require('./api/search');
52var securityLevel = require('./api/securityLevel');
53var serverInfo = require('./api/serverInfo');
54var settings = require('./api/settings');
55var sprint = require('./api/sprint');
56var status = require('./api/status');
57var statusCategory = require('./api/statusCategory');
58var user = require('./api/user');
59var version = require('./api/version');
60var webhook = require('./api/webhook');
61var workflow = require('./api/workflow');
62var workflowScheme = require('./api/workflowScheme');
63var worklog = require('./api/worklog');
64
65/**
66 * Represents a client for the Jira REST API
67 *
68 * @constructor JiraClient
69 * @property {AgileBoardClient} board
70 * @property {AgileSprintClient} sprint
71 *
72 * @property {ApplicationPropertiesClient} applicationProperties
73 * @property {AttachmentClient} attachment
74 * @property {AuditingClient} auditing
75 * @property {AuthClient} auth
76 * @property {AvatarClient} avatar
77 * @property {CommentClient} comment
78 * @property {ComponentClient} component
79 * @property {CustomFieldOptionClient} customFieldOption
80 * @property {DashboardClient} dashboard
81 * @property {FieldClient} field
82 * @property {FilterClient} filter
83 * @property {GroupClient} group
84 * @property {GroupUserPickerClient} groupUserPicker
85 * @property {GroupsClient} groups
86 * @property {IssueClient} issue
87 * @property {IssueLinkClient} issueLink
88 * @property {IssueLinkTypeClient} issueLinkType
89 * @property {IssueTypeClient} issueType
90 * @property {JqlClient} jql
91 * @property {LabelsClient} labels
92 * @property {LicenseRoleClient} licenseRole
93 * @property {LicenseValidatorClient} licenseValidator
94 * @property {MyPermissionsClient} myPermissions
95 * @property {MyPreferencesClient} myPreferences
96 * @property {MyselfClient} myself
97 * @property {PasswordClient} password
98 * @property {PermissionsClient} permissions
99 * @property {PermissionSchemeClient} permissionScheme
100 * @property {PriorityClient} priority
101 * @property {ProjectCategoryClient} projectCategory
102 * @property {ProjectClient} project
103 * @property {ProjectValidateClient} projectValidate
104 * @property {ReindexClient} reindex
105 * @property {ResolutionClient} resolution
106 * @property {RoleClient} roles
107 * @property {ScreensClient} screens
108 * @property {SearchClient} search
109 * @property {SecurityLevelClient} securityLevel
110 * @property {ServerInfoClient} serverInfo
111 * @property {SettingsClient} settings
112 * @property {StatusCategoryClient} statusCategory
113 * @property {StatusClient} status
114 * @property {UserClient} user
115 * @property {VersionClient} version
116 * @property {WebhookClient} webhook
117 * @property {WorkflowClient} workflow
118 * @property {WorkflowSchemeClient} workflowScheme
119 * @property {WorklogClient} worklog
120 *
121 * @param config The information needed to access the Jira API
122 * @param {string} config.host The hostname of the Jira API.
123 * @param {string} [config.protocol=https] The protocol used to accses the Jira API.
124 * @param {number} [config.port=443] The port number used to connect to Jira.
125 * @param {string} [config.path_prefix="/"] The prefix to use in front of the path, if Jira isn't at "/"
126 * @param {boolean} [config.strictSSL=true]
127 * @param {string} [config.version=2] The version of the Jira API to which you will be connecting. Currently, only
128 * version 2 is supported.
129 * @param {Object} [config.basic_auth] The authentication information used tp connect to Jira. Must contain EITHER username and password
130 * OR oauth information. Oauth information will be used over username/password authentication.
131 * @param {string} [config.basic_auth.username] The username of the user that will be authenticated. MUST be included
132 * if using username and password authentication.
133 * @param {string} [config.basic_auth.password] The password of the user that will be authenticated. MUST be included
134 * if using username and password authentication.
135 * @param {string} [config.oauth.consumer_key] The consumer key used in the Jira Application Link for oauth
136 * authentication. MUST be included if using OAuth.
137 * @param {string} [config.oauth.private_key] The private key used for OAuth security. MUST be included if using OAuth.
138 * @param {string} [config.oauth.token] The VERIFIED token used to connect to the Jira API. MUST be included if using
139 * OAuth.
140 * @param {string} [config.oauth.token_secret] The secret for the above token. MUST be included if using Oauth.
141 * @param {CookieJar} [config.cookie_jar] The CookieJar to use for every requests.
142 * @param {Promise} [config.promise] Any function (constructor) compatible with Promise (bluebird, Q,...).
143 * Default - native Promise.
144 * @param {Request} [config.request] Any function (constructor) compatible with Request (request, supertest,...).
145 * Default - require('request').
146 */
147
148var JiraClient = module.exports = function (config) {
149 if (!config.host) {
150 throw new Error(errorStrings.NO_HOST_ERROR);
151 }
152
153 this.host = config.host;
154 this.protocol = config.protocol ? config.protocol : 'https';
155 this.path_prefix = config.path_prefix ? config.path_prefix : '/';
156 this.port = config.port;
157 this.apiVersion = 2;
158 this.strictSSL = config.strictSSL || true;
159 this.agileApiVersion = '1.0';
160 this.authApiVersion = '1';
161 this.webhookApiVersion = '1.0';
162 this.promise = config.promise || Promise;
163 this.requestLib = config.request || request;
164 this.rejectUnauthorized = config.rejectUnauthorized;
165
166 if (config.oauth) {
167 if (!config.oauth.consumer_key) {
168 throw new Error(errorStrings.NO_CONSUMER_KEY_ERROR);
169 } else if (!config.oauth.private_key) {
170 throw new Error(errorStrings.NO_PRIVATE_KEY_ERROR);
171 } else if (!config.oauth.token) {
172 throw new Error(errorStrings.NO_OAUTH_TOKEN_ERROR);
173 } else if (!config.oauth.token_secret) {
174 throw new Error(errorStrings.NO_OAUTH_TOKEN_SECRET_ERROR);
175 }
176
177 this.oauthConfig = config.oauth;
178 this.oauthConfig.signature_method = 'RSA-SHA1';
179
180 } else if (config.basic_auth) {
181 if (config.basic_auth.base64) {
182 this.basic_auth = {
183 base64: config.basic_auth.base64
184 }
185 } else {
186 if (!config.basic_auth.username) {
187 throw new Error(errorStrings.NO_USERNAME_ERROR);
188 } else if (!config.basic_auth.password) {
189 throw new Error(errorStrings.NO_PASSWORD_ERROR);
190 }
191
192 this.basic_auth = {
193 user: config.basic_auth.username,
194 pass: config.basic_auth.password
195 };
196 }
197 }
198
199 if (config.cookie_jar) {
200 this.cookie_jar = config.cookie_jar;
201 }
202
203 this.applicationProperties = new applicationProperties(this);
204 this.attachment = new attachment(this);
205 this.auditing = new auditing(this);
206 this.auth = new auth(this);
207 this.avatar = new avatar(this);
208 this.backlog = new backlog(this);
209 this.board = new board(this);
210 this.comment = new comment(this);
211 this.component = new component(this);
212 this.customFieldOption = new customFieldOption(this);
213 this.dashboard = new dashboard(this);
214 this.epic = new epic(this);
215 this.field = new field(this);
216 this.filter = new filter(this);
217 this.group = new group(this);
218 this.groupUserPicker = new groupUserPicker(this);
219 this.groups = new groups(this);
220 this.issue = new issue(this);
221 this.issueLink = new issueLink(this);
222 this.issueLinkType = new issueLinkType(this);
223 this.issueType = new issueType(this);
224 this.jql = new jql(this);
225 this.labels = new labels(this);
226 this.licenseRole = new licenseRole(this);
227 this.licenseValidator = new licenseValidator(this);
228 this.myPermissions = new myPermissions(this);
229 this.myPreferences = new myPreferences(this);
230 this.myself = new myself(this);
231 this.password = new password(this);
232 this.permissions = new permissions(this);
233 this.permissionScheme = new permissionScheme(this);
234 this.priority = new priority(this);
235 this.project = new project(this);
236 this.projectCategory = new projectCategory(this);
237 this.projectValidate = new projectValidate(this);
238 this.reindex = new reindex(this);
239 this.resolution = new resolution(this);
240 this.roles = new roles(this);
241 this.screens = new screens(this);
242 this.search = new search(this);
243 this.securityLevel = new securityLevel(this);
244 this.serverInfo = new serverInfo(this);
245 this.settings = new settings(this);
246 this.sprint = new sprint(this);
247 this.status = new status(this);
248 this.statusCategory = new statusCategory(this);
249 this.user = new user(this);
250 this.version = new version(this);
251 this.webhook = new webhook(this);
252 this.workflow = new workflow(this);
253 this.workflowScheme = new workflowScheme(this);
254 this.worklog = new worklog(this);
255};
256
257(function () {
258
259 /**
260 * Simple utility to build a REST endpoint URL for the Jira API.
261 *
262 * @method buildURL
263 * @memberOf JiraClient#
264 * @param path The path of the URL without concern for the root of the REST API.
265 * @param {string | number} [forcedVersion] Use this param to force a particular version
266 * @returns {string} The constructed URL.
267 */
268 this.buildURL = function (path, forcedVersion) {
269 var apiBasePath = this.path_prefix + 'rest/api/';
270 var version = forcedVersion || this.apiVersion;
271 var requestUrl = url.format({
272 protocol: this.protocol,
273 hostname: this.host,
274 port: this.port,
275 pathname: apiBasePath + version + path
276 });
277
278 return decodeURIComponent(requestUrl);
279 };
280
281 /**
282 * Simple utility to build a REST endpoint URL for the Jira Agile API.
283 *
284 * @method buildAgileURL
285 * @memberOf JiraClient#
286 * @param path The path of the URL without concern for the root of the REST API.
287 * @param {string | number} [forcedVersion] Use this param to force a particular version
288 * @returns {string} The constructed URL.
289 */
290 this.buildAgileURL = function (path, forcedVersion) {
291 var apiBasePath = this.path_prefix + 'rest/agile/';
292 var version = forcedVersion || this.agileApiVersion;
293 var requestUrl = url.format({
294 protocol: this.protocol,
295 hostname: this.host,
296 port: this.port,
297 pathname: apiBasePath + version + path
298 });
299
300 return decodeURIComponent(requestUrl);
301 };
302
303 /**
304 * Simple utility to build a REST endpoint URL for the Jira Auth API.
305 *
306 * @method buildAuthURL
307 * @memberOf JiraClient#
308 * @param path The path of the URL without concern for the root of the REST API.
309 * @param {string | number} [forcedVersion] Use this param to force a particular version
310 * @returns {string} The constructed URL.
311 */
312 this.buildAuthURL = function (path, forcedVersion) {
313 var apiBasePath = this.path_prefix + 'rest/auth/';
314 var version = forcedVersion || this.authApiVersion;
315 var requestUrl = url.format({
316 protocol: this.protocol,
317 hostname: this.host,
318 port: this.port,
319 pathname: apiBasePath + version + path
320 });
321
322 return decodeURIComponent(requestUrl);
323 };
324
325 /**
326 * Simple utility to build a REST endpoint URL for the Jira webhook API.
327 *
328 * @method buildWebhookURL
329 * @memberOf JiraClient#
330 * @param path The path of the URL without concern for the root of the REST API.
331 * @param {string | number} [forcedVersion] Use this param to force a particular version
332 * @returns {string} The constructed URL.
333 */
334 this.buildWebhookURL = function (path, forcedVersion) {
335 var apiBasePath = this.path_prefix + 'rest/webhooks/';
336 var version = forcedVersion || this.webhookApiVersion;
337 var requestUrl = url.format({
338 protocol: this.protocol,
339 hostname: this.host,
340 port: this.port,
341 pathname: apiBasePath + version + path
342 });
343
344 return decodeURIComponent(requestUrl);
345 };
346
347 /**
348 * Make a request to the Jira API and call back with it's response.
349 *
350 * @method makeRequest
351 * @memberOf JiraClient#
352 * @param options The request options.
353 * @param [callback] Called with the APIs response.
354 * @param {string} [successString] If supplied, this is reported instead of the response body.
355 * @return {Promise} Resolved with APIs response or rejected with error
356 */
357 this.makeRequest = function (options, callback, successString) {
358 let requestLib = this.requestLib;
359 options.rejectUnauthorized = this.rejectUnauthorized;
360 options.strictSSL = this.strictSSL;
361
362 if (this.oauthConfig) {
363 options.oauth = this.oauthConfig;
364 } else if (this.basic_auth) {
365 if (this.basic_auth.base64) {
366 if (!options.headers) {
367 options.headers = {}
368 }
369 options.headers['Authorization'] = 'Basic ' + this.basic_auth.base64
370 } else {
371 options.auth = this.basic_auth;
372 }
373 }
374 if (this.cookie_jar) {
375 options.jar = this.cookie_jar;
376 }
377
378 if (callback) {
379 requestLib(options, function (err, response, body) {
380 if (
381 err
382 || (
383 response.statusCode.toString()[0] !== "2"
384 && response.statusCode.toString()[0] !== "3"
385 )
386 ) {
387 return callback(err ? err : body, null, response);
388 }
389
390 if (typeof body == 'string') {
391 try {
392 body = JSON.parse(body);
393 } catch (jsonErr) {
394 return callback(jsonErr, null, response);
395 }
396 }
397
398 return callback(null, successString ? successString : body, response);
399 });
400 } else if (this.promise) {
401 return new this.promise(function (resolve, reject) {
402
403 var req = requestLib(options);
404 var requestObj = null;
405
406 req.on('request', function (request) {
407 requestObj = request;
408 });
409
410 req.on('response', function (response) {
411
412 // Saving error
413 var error = response.statusCode.toString()[0] !== '2';
414
415 // Collecting data
416 var body = [];
417 var push = body.push.bind(body);
418 response.on('data', push);
419
420 // Data collected
421 response.on('end', function () {
422
423 var result = body.join('');
424
425 // Parsing JSON
426 if (result[0] === '[' || result[0] === '{') {
427 try {
428 result = JSON.parse(result);
429 } catch (e) {
430 // nothing to do
431 }
432 }
433
434 if (error) {
435 response.body = result;
436 if (options.debug) {
437 reject({
438 result: JSON.stringify(response),
439 debug: {
440 options: options,
441 request: {
442 headers: requestObj._headers,
443 },
444 response: {
445 headers: response.headers,
446 },
447 }
448 });
449 } else {
450 reject(JSON.stringify(response));
451 }
452 return;
453 }
454
455 if (options.debug) {
456 resolve({
457 result,
458 debug: {
459 options: options,
460 request: {
461 headers: requestObj._headers,
462 },
463 response: {
464 headers: response.headers,
465 },
466 }
467 });
468 } else {
469 resolve(result);
470 }
471 });
472
473 });
474
475 req.on('error', reject);
476
477 });
478 }
479
480 };
481
482}).call(JiraClient.prototype);
483
484JiraClient.oauth_util = require('./lib/oauth_util');
485
486exports.oauth_util = oauth_util;