UNPKG

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