class.SWIFT_JIRABridge.php

Amarjeet Kaur, 01/21/2013 12:21 am

Download (36.7 kB)

 
1
<?php
2
3
/**
4
 * =======================================
5
 * ###################################
6
 * SWIFT Framework
7
 *
8
 * @package        SWIFT
9
 * @author         Kayako Infotech Ltd.
10
 * @copyright      Copyright (c) 2001-2009, Kayako Infotech Ltd.
11
 * @license        http://www.kayako.com/license
12
 * @link           http://www.kayako.com
13
 * @filesource
14
 * ###################################
15
 * =======================================
16
 */
17
18
/**
19
 * JIRA Bridge
20
 * Handles all the JIRA interactions to and from Kayako Fusion
21
 *
22
 * @author Abhinav Kumar <abhinav.kumar@kayako.com>
23
 */
24
class SWIFT_JIRABridge extends SWIFT_Library
25
{
26
        /*
27
         * =============================================
28
         * Access Details
29
         * =============================================
30
         */
31
32
        /**
33
         * JIRA Url
34
         * e.g. http://localhost:8080
35
         *
36
         * @var string
37
         */
38
        private $_url;
39
40
        /**
41
         * user name to access JIRA
42
         * e. g. admin
43
         *
44
         * @var admin
45
         */
46
        private $_userName;
47
48
        /**
49
         * password to access JIRA
50
         *
51
         * @var password
52
         */
53
        private $_password;
54
55
        /**
56
         * Authentication token
57
         *
58
         * @var string
59
         */
60
        private $_authToken;
61
62
        /**
63
         * Timeout in seconds to connect to the JIRA webservice
64
         *
65
         * @var type
66
         */
67
        private $_connectionTimeout;
68
69
        /*
70
         * =============================================
71
         * Project Details
72
         * =============================================
73
         */
74
75
        /**
76
         * Default project key to post issues in
77
         * e.g. TEST
78
         *
79
         * @var string
80
         */
81
        private $_projectKey;
82
83
        /*
84
         * =============================================
85
         * Bridge Details
86
         * =============================================
87
         */
88
89
        /**
90
         * HTTP Client for connecting & making the API requests to the JIRA web service
91
         *
92
         * @var \SWIFT_HTTPClient
93
         */
94
        private $Client;
95
96
        /**
97
         * Table name in the Kayako DB
98
         * default : TABLE_PREFIX . jira_issues
99
         *
100
         * @var string
101
         */
102
        private static $_tableName = 'jiraissues';
103
104
        /**
105
         * Single Instance to be used for Singleton JIRABridge
106
         *
107
         * @var \SWIFT_JIRABridge
108
         */
109
        private static $_Instance = null;
110
111
        /**
112
         * JIRA create issue meta data
113
         *
114
         * @var mixed
115
         */
116
        private static $_Meta;
117
118
        /**
119
         * The last error message
120
         *
121
         * @var string
122
         */
123
        private $_error = 'No Error';
124
125
        /**
126
         * The default constructor
127
         * Reads & initializes the module settings from SWIFT
128
         * Prepares the basic JIRA authentication
129
         *
130
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
131
         * @return bool 'TRUE' on success and 'FALSE' otherwise
132
         */
133
        public function __construct()
134
        {
135
                parent::__construct();
136
137
                $_SWIFT = SWIFT::GetInstance();
138
139
                if (!$_SWIFT->Settings->Get('bj_isenabled')) {
140
                        return false;
141
                }
142
143
                $this->_url               = $_SWIFT->Settings->Get('bj_jiraurl');
144
                $this->_userName          = $_SWIFT->Settings->Get('bj_username');
145
                $this->_password          = $_SWIFT->Settings->Get('bj_password');
146
                $this->_connectionTimeout = $_SWIFT->Settings->Get('bj_timeout') ? $_SWIFT->Settings->Get('bj_timeout') : 1;
147
148
                $this->_projectKey = strtoupper($_SWIFT->Settings->Get('bj_defaultProject'));
149
150
                $this->_authToken = base64_encode($this->_userName . ':' . $this->_password);
151
152
                $this->Load->Library('HTTP:HTTPClient', array(), true, 'jira');
153
                $this->Load->Library('HTTP:HTTPAdapter_Curl', array(), true, 'jira');
154
                $this->Load->Library('JIRA:JIRAComment', false, false);
155
                $this->Load->LoadApp('Ticket:Ticket', APP_TICKETS);
156
157
                $this->Client = new SWIFT_HTTPClient($this->_url);
158
159
                $_Adapter = new SWIFT_HTTPAdapter_Curl();
160
161
                $_Adapter->AddOption('CURLOPT_CONNECTTIMEOUT', $this->_connectionTimeout);
162
                $_Adapter->AddOption('CURLOPT_TIMEOUT', $this->_connectionTimeout);
163
164
                $_Adapter->SetEncoding(SWIFT_HTTPBase::RESPONSETYPE_JSON);
165
166
                $this->Client->SetAdapter($_Adapter);
167
168
                $this->Client->SetHeaders('Authorization', 'Basic ' . $this->_authToken);
169
                $this->Client->SetHeaders('Accept', 'application/json');
170
                $this->Client->SetHeaders('Content-Type', 'application/json');
171
        }
172
173
        /**
174
         * The default destructor
175
         *
176
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
177
         * @return bool 'TRUE' on success & 'FALSE' otherwise
178
         */
179
        public function __destruct()
180
        {
181
                return parent::__destruct();
182
        }
183
184
        /**
185
         * Creates an JIRA Issue with the provided associated array $_data
186
         * prepares the 'POST' body for the request & finally fires the REST request
187
         * More Info on the REST API : https://developer.atlassian.com/display/JIRADEV/JIRA+REST+API+Example+-+Create+Issue
188
         *
189
         * @param mixed $_data an associative array of issue parametres
190
         *
191
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
192
         * @return \SWIFT_JIRAIssue on success and 'FALSE' otherwise
193
         */
194
        public function CreateIssue($_data)
195
        {
196
                if (!$this->GetIsClassLoaded()) {
197
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
198
                }
199
200
                if (array_key_exists('project', $_data) && $_data['project'] != '') {
201
                        $_projectKey = $_data['project'];
202
                } else {
203
                        $_projectKey = $this->_projectKey;
204
                }
205
206
                if (array_key_exists('labels', $_data)) {
207
                        if (_is_array($_data['labels'])) {
208
                                $_data['labels'][] = 'Kayako';
209
                                $_labels           = $_data['labels'];
210
                        }
211
                } else {
212
                        $_labels = array('Kayako');
213
                }
214
215
                $this->Client->setUri($this->_url . 'rest/api/latest/issue');
216
217
                $_fields = array(
218
                        'project'     => array(
219
                                'key' => $_projectKey
220
                        ),
221
                        'summary'     => $_data['summary'],
222
                        'description' => $_data['description'],
223
                        'issuetype'   => array(
224
                                'id' => $_data['issueType']
225
                        ),
226
                        'priority'    => array(
227
                                'id' => $_data['priority']
228
                        ),
229
                        'labels'      => $_labels
230
                );
231
232
                if (array_key_exists('security', $_data) && !empty($_data['security'])) {
233
                        $_fields['security'] = array(
234
                                'id' => $_data['security']
235
                        );
236
                }
237
238
                $this->Client->SetParameterPost('fields', $_fields);
239
240
                //Body prepared . . .time to fire the Request
241
                $_Response = $this->Client->Request(SWIFT_HTTPBase::POST, $this->_connectionTimeout);
242
243
                //Check if the response is not an error
244
                if ($_Response !== false) {
245
                        if ($_Response->isSuccessful()) {
246
                                //seems good so far . . .readh the response body
247
                                $_Decoded = json_decode($_Response->getBody());
248
249
                                if ($_Decoded) {
250
                                        if (isset($_Decoded->id) && isset($_Decoded->key)) {
251
                                                $_data['id']  = $_Decoded->id;
252
                                                $_data['key'] = $_Decoded->key;
253
254
                                                //We are almost there . . . time to create a local record for Ticket <->Issue reference
255
                                                $this->Load->Library('JIRA:JIRAIssueManager', false, false, 'jira');
256
                                                $_SWIFT = SWIFT::GetInstance();
257
                                                $_SWIFT->Database->AutoExecute(TABLE_PREFIX . self::$_tableName, array(
258
                                                                                                                                                                                          'ticketid' => $_SWIFT->Database->Escape($_data['kayakoTicketId']),
259
                                                                                                                                                                                          'issueid'  => $_SWIFT->Database->Escape($_data['id']),
260
                                                                                                                                                                                          'issuekey' => $_SWIFT->Database->Escape($_data['key'])
261
                                                                                                                                                                                 ), 'INSERT');
262
263
                                                $_SWIFTTicketObject = SWIFT_Ticket::GetObjectOnID($_data['kayakoTicketId']);
264
                                                $_ticketSummary     = '';
265
266
                                                if ($_SWIFTTicketObject && $_SWIFTTicketObject instanceof SWIFT_Ticket && $_SWIFTTicketObject->GetIsClassLoaded()) {
267
                                                        $_title         = $_SWIFTTicketObject->GetTicketDisplayID();
268
                                                        $_ticketSummary = $_SWIFTTicketObject->GetProperty('subject');
269
                                                } else {
270
                                                        $_title         = $this->Language->Get('jira_kayakoticket');
271
                                                        $_ticketSummary = '';
272
                                                }
273
274
                                                $_ticketURL = SWIFT::Get('basename') . '/Tickets/Ticket/View/' . $_data['kayakoTicketId'];
275
276
                                                if (!$_SWIFT->Settings->Get('bj_jiraissuelinking') || $this->PostRemoteLink($_data['key'], $_ticketURL, $_title, $_ticketSummary)) {
277
                                                        //Finally, create and return a new SWIFT_JIRAIssueManger object
278
                                                        return new SWIFT_JIRAIssueManager($_data);
279
                                                } else {
280
                                                        $this->SetErrorMessage($this->Language->Get('jira_issuelinkingfail'));
281
                                                }
282
                                        } else {
283
                                                $this->SetErrorMessage($this->Language->Get('jira_error'));
284
                                        }
285
                                } else {
286
                                        $this->SetErrorMessage($this->Language->Get('jira_error'));
287
                                }
288
                        } else {
289
                                $this->SetErrorMessage($this->parseErrorMessage($_Response));
290
                        }
291
                }
292
293
                return false;
294
        }
295
296
        /**
297
         * GetInstance method for ensuring a single instance per application is created
298
         * Tests the connection and returns 'FALSE' if the connection is lost
299
         *
300
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
301
         * @return mixed SWIFT_JIRABridge on success and 'FALSE' otherwise
302
         */
303
        public static function GetInstance()
304
        {
305
                if (!self::$_Instance) {
306
                        self::$_Instance = new SWIFT_JIRABridge();
307
                }
308
309
                return self::$_Instance;
310
        }
311
312
        /**
313
         * Calls the JIRA REST API and checks if an issue is still active in JIRA
314
         * If an issue is not found on JIRA deletes the corresponding entry from the
315
         * Kayako database.
316
         *
317
         * @param mixed $_issueID - Issue key or id
318
         *
319
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
320
         * @return boolean 'TRUE' if the issue is still active and 'FALSE' otherwise
321
         */
322
        public function IsIssueValid($_issueKey = null)
323
        {
324
                if (!$this->GetIsClassLoaded()) {
325
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
326
                }
327
328
                if ($_issueKey === null) {
329
                        return false;
330
                }
331
332
                if(!$this->Client) {
333
                        return false;
334
                }
335
336
                $this->Client->setUri($this->_url . 'rest/api/latest/issue/' . $_issueKey);
337
338
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
339
340
                if (!$_Response || !$_Response->isSuccessful()) {
341
                        return false;
342
                }
343
344
                $_Decoded = json_decode($_Response->getBody());
345
346
                if (isset($_Decoded->errorMessages)) {
347
                        /**
348
                         * Issue seems to have been deleted
349
                         * Delete from kayako database as well & return FALSE
350
                         */
351
                        $_Sql = 'DELETE FROM ' . TABLE_PREFIX . self::$_tableName .
352
                                ' WHERE issueid = ' . $this->Database->Escape($_issueKey);
353
354
                        $this->Database->Execute($_Sql);
355
356
                        return false;
357
                }
358
                return true;
359
        }
360
361
362
        /**
363
         * Calls the JIRA REST API and checks if an issue is still active in JIRA
364
         * If an issue is not found on JIRA deletes the corresponding entry from the
365
         * Kayako database.
366
         *
367
         * @param mixed $_issueID - Issue key or id
368
         *
369
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
370
         * @return boolean 'TRUE' if the issue is still active and 'FALSE' otherwise
371
         */
372
        public function IsProjectValid($_projectKey = null)
373
        {
374
                if (!$this->GetIsClassLoaded()) {
375
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
376
                }
377
378
                if (null == $_projectKey) {
379
                        return false;
380
                }
381
382
                if (!$this->Test()) {
383
                        return false;
384
                }
385
386
387
                $this->Client->setUri($this->_url . 'rest/api/latest/project/' . $_projectKey);
388
389
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
390
391
                if ($_Response && $_Response->isSuccessful()) {
392
                        return true;
393
                }
394
395
                return false;
396
        }
397
398
        /**
399
         * Parses a JSON decoded response &
400
         * Converts that into an \SWIFT_JIRAIssue
401
         *
402
         * @param \stdClass $_JSONDecoded - Decoded PHP object
403
         *
404
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
405
         * @return \SWIFT_JIRAIssue
406
         */
407
        public function ParseResponse($_JSONDecoded)
408
        {
409
                if (!$this->GetIsClassLoaded()) {
410
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
411
                }
412
413
                $_Data = array();
414
415
                $_dataStore = $this->Database->QueryFetch("SELECT ticketid FROM " . TABLE_PREFIX . self::$_tableName . " WHERE issueid = '" .
416
                        intval($_JSONDecoded->id) . "'");
417
418
                $_Data['id']             = $_JSONDecoded->id;
419
                $_Data['key']            = $_JSONDecoded->key;
420
                $_Data['project']        = $_JSONDecoded->fields->project->key;
421
                $_Data['status']         = $_JSONDecoded->fields->status->name;
422
                $_Data['commentsCount']  = $_JSONDecoded->fields->comment->total;
423
                $_Data['issueType']      = $_JSONDecoded->fields->issuetype->name;
424
                $_Data['summary']        = $_JSONDecoded->fields->summary;
425
                $_Data['kayakoTicketId'] = $_dataStore['ticketid'];
426
                $_Data['priority']       = $_JSONDecoded->fields->priority->name;
427
                $_Data['assignee']       = isset($_JSONDecoded->fields->assignee->displayName) ? $_JSONDecoded->fields->assignee->displayName : "Unassigned";
428
                $_Data['reporter']       = $_JSONDecoded->fields->reporter->name;
429
                $_Data['description']    = $_JSONDecoded->fields->description;
430
                $_Data['labels']         = $_JSONDecoded->fields->labels;
431
                $_Data['created']        = strtotime($_JSONDecoded->fields->created);
432
                $_Data['updated']        = strtotime($_JSONDecoded->fields->updated);
433
434
                $this->Load->Library('JIRA:JIRAIssueManager', false, false, 'jira');
435
436
                return new SWIFT_JIRAIssueManager($_Data);
437
        }
438
439
        /**
440
         * Calls the JIRA REST Api and fetches the issue details
441
         *
442
         * @param mixed $_issueID issue key | issue id
443
         *
444
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
445
         * @return \SWIFT_JIRAIssue on success and 'FALSE' otherwise
446
         */
447
        public function Get($_issueID)
448
        {
449
                if (!$this->GetIsClassLoaded()) {
450
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
451
                }
452
453
                if (empty($_issueID) || !$this->IsIssueValid($_issueID)) {
454
                        return false;
455
                }
456
457
                $_apiURL = $this->_url . 'rest/api/latest/issue/' . $_issueID;
458
459
                $this->Client->setUri($_apiURL);
460
461
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
462
463
                if ($_Response && $_Response->isSuccessful()) {
464
                        $_Decoded = json_decode($_Response->getBody());
465
466
                        return $this->ParseResponse($_Decoded);
467
                }
468
469
                return false;
470
        }
471
472
        /**
473
         * Fetches ONE JIRA Issue based on passed parameter from the local database
474
         *
475
         * @param string $_param the search parameter
476
         * @param string $_value the search value
477
         *
478
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
479
         * @return \SWIFT_JIRAIssue on success and 'FALSE' otherwise
480
         */
481
        public function GetIssueBy($_param, $_value)
482
        {
483
                if (!$this->GetIsClassLoaded()) {
484
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
485
                }
486
487
                $_query = "SELECT * FROM " . TABLE_PREFIX . self::$_tableName . " WHERE " . $this->Database->Escape($_param) . " = '" .
488
                        $this->Database->Escape($_value) . "'";
489
490
                $_DataStore = $this->Database->QueryFetch($_query);
491
                $this->Load->Library('JIRA:JIRAIssueManager', false, false, 'jira');
492
                if ($this->IsIssueValid($_DataStore['issueid'])) {
493
                        return $this->Get($_DataStore['issueid']);
494
                }
495
496
                return false;
497
        }
498
499
        /**
500
         * Fetches All the JIRA Issue based on passed parameter from the local database
501
         *
502
         * @param string $_param the search parameter
503
         * @param string $_value the search value
504
         *
505
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
506
         * @return mixed an array of \SWIFT_JIRAIssue on success and 'FALSE' otherwise
507
         */
508
        public function GetIssuesBy($_param, $_value)
509
        {
510
                if (!$this->GetIsClassLoaded()) {
511
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
512
                }
513
514
                $_Query     = "SELECT * FROM " . TABLE_PREFIX . self::$_tableName . " WHERE " . $this->Database->Escape($_param) . " = '" .
515
                        $this->Database->Escape($_value) . "'";
516
                $_DataStore = $this->Database->QueryFetchAll($_Query);
517
518
                $_issues = array();
519
520
                $this->Load->Library('JIRA:JIRAIssueManager', false, false, 'jira');
521
522
                foreach ($_DataStore as $_Data) {
523
                        if ($this->IsIssueValid($_Data['issuekey'])) {
524
                                $_issues[] = $this->Get($_Data['issuekey']);
525
                        }
526
                }
527
528
                if (_is_array($_issues)) {
529
                        return $_issues;
530
                } else {
531
                        return false;
532
                }
533
        }
534
535
        /**
536
         * Fetches the available issue types from JIRA REST API
537
         *
538
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
539
         * @return mixed json decoded object on success and 'FALSE' otherwise
540
         */
541
        public function GetIssueTypes()
542
        {
543
                if (!$this->GetIsClassLoaded()) {
544
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
545
                }
546
547
                $this->Client->setUri($this->_url . 'rest/api/latest/issuetype');
548
549
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
550
551
                if ($_Response && $_Response->isSuccessful()) {
552
                        return json_decode($_Response->getBody());
553
                }
554
555
                return false;
556
        }
557
558
        /**
559
         * Fetches the available issue types from JIRA REST API
560
         *
561
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
562
         * @return mixed json decoded object on success and 'FALSE' otherwise
563
         */
564
        public function GetIssueTypesByProject($_projectKey)
565
        {
566
                if (!$this->GetIsClassLoaded()) {
567
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
568
                }
569
570
                if (empty($_projectKey)) {
571
                        throw new SWIFT_Exception('Project Key ' . $this->Language->Get('jira_noempty'));
572
                }
573
574
                if (!empty($_projectKey) && is_string($_projectKey) && $this->isProjectValid($_projectKey)) {
575
                        $_apiURL = $this->_url . 'rest/api/latest/project/' . $_projectKey;
576
                        $this->Client->setUri($_apiURL);
577
578
                        $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
579
580
                        if ($_Response && $_Response->isSuccessful()) {
581
                                $_Decoded = json_decode($_Response->getBody());
582
                                if ($_Decoded && isset($_Decoded->issueTypes)) {
583
                                        return $_Decoded->issueTypes;
584
                                }
585
                        }
586
587
                        return false;
588
                } else {
589
                        echo 'No project key specified or project ', $_projectKey, ' not found';
590
                }
591
592
                return false;
593
        }
594
595
        /**
596
         * Fetches the available security levels from JIRA REST API
597
         *
598
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
599
         * @return mixed json decoded object on success and 'FALSE' otherwise
600
         */
601
        public function GetSecurityLevelsByProject($_projectKey, $_issueType)
602
        {
603
                if (!$this->GetIsClassLoaded()) {
604
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
605
                }
606
607
                $_SWIFT = SWIFT::GetInstance();
608
609
                if (empty($_projectKey)) {
610
                        throw new SWIFT_Exception('Project Key ' . $_SWIFT->Language->Get('jira_noempty'));
611
                }
612
613
                if (!$this->IsProjectValid($_projectKey)) {
614
                        throw new SWIFT_Exception($_projectKey . ' is not a valid project');
615
                }
616
617
                $_CreateMeta = $this->GetCreateMeta();
618
619
                if ($_CreateMeta && _is_array($_CreateMeta) && array_key_exists($_projectKey, $_CreateMeta)) {
620
                        if (array_key_exists('security', $_CreateMeta[$_projectKey])) {
621
                                return $_CreateMeta[$_projectKey]['security'];
622
                        }
623
624
                        return false;
625
                }
626
//                $_Meta = $this->GetCreateMetaByProject($_projectKey, $_issueType);
627
//
628
//                if ($_Meta) {
629
//                        if (isset($_Meta->projects[0]->issuetypes[0]->fields->security->allowedValues)) {
630
//                                return $_Meta->projects[0]->issuetypes[0]->fields->security->allowedValues;
631
//                        }
632
//                }
633
                return false;
634
        }
635
636
        /**
637
         * Fetches the available issue priorities from JIRA REST API
638
         *
639
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
640
         * @return mixed json decoded object on success and 'FALSE' otherwise
641
         */
642
        public function GetPriorities()
643
        {
644
                if (!$this->GetIsClassLoaded()) {
645
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
646
                }
647
648
                $_SWIFT = SWIFT::GetInstance();
649
650
                $_JIRAPriorities = $_SWIFT->Cache->Get('jirapriorities');
651
652
                if (!$_JIRAPriorities || !_is_array($_JIRAPriorities)) {
653
                        $this->Client->setUri($this->_url . 'rest/api/latest/priority');
654
655
                        $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
656
                        if ($_Response && $_Response->isSuccessful()) {
657
658
                                $_PrioritiesDecoded = json_decode($_Response->getBody());
659
                                if ($_PrioritiesDecoded && _is_array($_PrioritiesDecoded)) {
660
661
                                        $_prioritiesContainer = array();
662
                                        foreach ($_PrioritiesDecoded as $_Priority) {
663
                                                $_prioritiesContainer[] = array(
664
                                                        'title' => $_Priority->name,
665
                                                        'value' => $_Priority->id
666
                                                );
667
                                        }
668
669
                                        if (_is_array($_prioritiesContainer)) {
670
                                                $_SWIFT->Cache->Update('jirapriorities', $_prioritiesContainer);
671
                                        }
672
                                }
673
                        }
674
                }
675
676
                return $_SWIFT->Cache->Get('jirapriorities');
677
        }
678
679
        /**
680
         * Fetches the available projects from JIRA REST API
681
         *
682
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
683
         * @return mixed json decoded object on success and 'FALSE' otherwise
684
         */
685
        public function GetProjects()
686
        {
687
                if (!$this->GetIsClassLoaded()) {
688
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
689
                }
690
691
                $_SWIFT = SWIFT::GetInstance();
692
693
                $_JIRAProjects = $_SWIFT->Cache->Get('jiraprojects');
694
695
                if (!$_JIRAProjects || !_is_array($_JIRAProjects)) {
696
                        $this->Client->setUri($this->_url . 'rest/api/latest/project');
697
698
                        $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
699
700
                        // echo 'Response received <pre><br/>', $_Response->getRawData(), '</pre><br/>';
701
                        if ($_Response && $_Response->isSuccessful()) {
702
                                $_JIRAProjects = json_decode($_Response->getBody());
703
704
                                if (_is_array($_JIRAProjects)) {
705
                                        $_cachedProjects = array();
706
                                        foreach ($_JIRAProjects as $_Project) {
707
                                                $_cachedProject    = array(
708
                                                        'title' => $_Project->name,
709
                                                        'value' => $_Project->key
710
                                                );
711
                                                $_cachedProjects[] = $_cachedProject;
712
                                        }
713
                                } else {
714
                                        if ($_JIRAProjects) {
715
                                                $_cachedProjects = array(
716
                                                        'title' => $_Projects->name,
717
                                                        'value' => $_Projects->id
718
                                                );
719
                                        }
720
                                }
721
722
                                if (_is_array($_cachedProjects)) {
723
                                        $_SWIFT->Cache->Update('jiraprojects', $_cachedProjects);
724
                                } else {
725
                                        $this->SetErrorMessage('jira_noprojectsloaded');
726
727
                                        return false;
728
                                }
729
                        } else {
730
                                $this->SetErrorMessage('No Projects found');
731
                        }
732
                }
733
734
                return $_SWIFT->Cache->Get('jiraprojects');
735
        }
736
737
        /**
738
         * Not Implemented yet
739
         *
740
         * @return boolean
741
         */
742
        public function GetReporters()
743
        {
744
                return false;
745
                $this->Client->setUri($this->_url . 'rest/api/latest/project');
746
747
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
748
749
                if ($_Response && $_Response->isSuccessful()) {
750
                        return json_decode($_Response->getBody());
751
                }
752
753
                return false;
754
        }
755
756
        /**
757
         * Reads and parses an error message returned from an JIRA REST API Request
758
         *
759
         * @param SWIFT_HTTPResponse $_Response
760
         *
761
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
762
         * @return string the error message or FALSE(bool) if no error is read
763
         */
764
        protected function parseErrorMessage(SWIFT_HTTPResponse $_Response)
765
        {
766
                $_Decoded = json_decode($_Response->getBody());
767
768
                $_parsedErrors = '';
769
770
                if ($_Decoded) {
771
                        if (isset($_Decoded->errors)) {
772
                                $_errors = $_Decoded->errors;
773
                                foreach ($_errors as $_Key => $_Val) {
774
                                        $_parsedErrors .= $_Val . PHP_EOL;
775
                                }
776
                        }
777
                        if (isset($_Decoded->errorMessages)) {
778
                                foreach ($_Decoded->errorMessages as $_errorMessage) {
779
                                        $_parsedErrors .= $_errorMessage . PHP_EOL;
780
                                }
781
                        }
782
783
                        return $_parsedErrors;
784
                }
785
786
                return false;
787
        }
788
789
        /**
790
         * Unlinks a JIRA Issue from a Kayako Support Ticket
791
         *
792
         * @param string $_issueKey The issue key to unlink
793
         *
794
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
795
         * @return boolean 'TRUE' on success & 'FALSE' otherwise
796
         * @throws SWIFT_Exception
797
         */
798
        public function UnlinkIssue($_issueKey, $_ticketID)
799
        {
800
                if (!$this->GetIsClassLoaded()) {
801
                        throw new SWIFT_Exception(__CLASS__ . ' - ' . SWIFT_CLASSNOTLOADED);
802
                }
803
804
                if ($_issueKey) {
805
                        $_JIRAIssue = $this->GetIssueBy('issuekey', $_issueKey);
806
807
                        if ($_JIRAIssue) {
808
                                $_SWIFT              = SWIFT::GetInstance();
809
                                $_SWIFT_TicketObject = SWIFT_Ticket::GetObjectOnID($_ticketID);
810
                                $_JIRAComment        = new SWIFT_JIRAComment();
811
                                $_JIRAComment->SetBody(sprintf($this->Language->Get('unlinkedFromJIRA'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Staff->GetProperty('fullname')));
812
                                if ($_JIRAIssue->PostComment($_JIRAComment) !== false) {
813
                                        if ($this->RemoveRemoteLink($_issueKey, $_ticketID)) {
814
                                                /**
815
                                                 * Comment posted & Remote link removed
816
                                                 * Delete from kayako database as well & return TRUE
817
                                                 */
818
                                                $_query = 'DELETE FROM ' . TABLE_PREFIX . self::$_tableName
819
                                                        . ' WHERE issuekey=\'' . $_issueKey . '\'';
820
821
                                                if ($this->Database->Execute($_query) !== false) {
822
                                                        return true;
823
                                                }
824
                                        }
825
                                } else {
826
                                        $this->SetErrorMessage($this->Language->Get('jira_error') . ' ' . $this->Language->Get('jira_comment_notposted'));
827
828
                                        return false;
829
                                }
830
                        } else {
831
                                $this->SetErrorMessage($this->Language->Get('jira_noissuekey'));
832
833
                                return false;
834
                        }
835
                } else {
836
                        $this->SetErrorMessage($this->Language->Get('jira_noissuekey'));
837
838
                        return false;
839
                }
840
        }
841
842
        /**
843
         * Posts a comment to JIRA
844
         *
845
         * @param SWIFT_JIRAComment $_Comment
846
         *
847
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
848
         * @return boolean 'TRUE' on success & 'FALSE' otherwise
849
         * @throws SWIFT_Exception
850
         */
851
        public function PostComment(SWIFT_JIRAComment $_Comment = null)
852
        {
853
                if (!$this->GetIsClassLoaded()) {
854
                        throw new SWIFT_Exception(__CLASS__ . ' - ' . SWIFT_CLASSNOTLOADED);
855
                }
856
857
                if ($_Comment) {
858
                        if (!is_string($_Comment->GetBody())) {
859
                                throw new SWIFT_Exception(SWIFT_INVALIDDATA);
860
                        }
861
862
                        $_JIRAIssue = $_Comment->GetIssue();
863
864
                        $_commentBody = $_Comment->GetBody();
865
866
                        $_visibility = $_Comment->GetVisibility();
867
868
                        if ($_JIRAIssue) {
869
                                $_apiURL = $this->_url . 'rest/api/latest/issue/' . $_JIRAIssue->GetKey() . '/comment';
870
871
                                $this->Client->setUri($_apiURL);
872
873
                                $this->Client->SetParameterPost('body', $_commentBody);
874
875
                                if ($_visibility && _is_array($_visibility) && array_key_exists('type', $_visibility) && array_key_exists('value', $_visibility)) {
876
                                        $this->Client->SetParameterPost('visibility', $_visibility);
877
                                }
878
879
                                $_Response = $this->Client->Request(SWIFT_HTTPBase::POST, $this->_connectionTimeout);
880
881
                                if ($_Response && $_Response->isSuccessful()) {
882
                                        $_ResponseDecoded = json_decode($_Response->getBody());
883
884
                                        return $_ResponseDecoded->id;
885
                                }
886
887
                                return false;
888
                        }
889
                        $this->_error = $this->Language->Get('jira_noissuefound');
890
891
                        return false;
892
                }
893
894
                return false;
895
        }
896
897
        public function GetCreateMeta()
898
        {
899
                $_SWIFT = SWIFT::GetInstance();
900
901
                $_CreateMetaCached = $_SWIFT->Cache->Get('jiracreatemeta');
902
903
                if ($_CreateMetaCached) {
904
                        return $_CreateMetaCached;
905
                }
906
907
                $_queryArray = array(
908
                        'expand' => 'projects.issuetypes.fields'
909
                );
910
911
                $_query = http_build_query($_queryArray);
912
913
                $_apiURL = $this->_url . 'rest/api/2/issue/createmeta?' . $_query;
914
915
                $this->Client->setUri($_apiURL);
916
917
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
918
919
                if ($_Response && $_Response->isSuccessful()) {
920
                        $_CreateMeta          = json_decode($_Response->getBody());
921
                        $_CreateMetaContainer = $_ProjectCreateMeta = array();
922
                        foreach ($_CreateMeta->projects as $_Project) {
923
                                $_issueTypes = array();
924
                                foreach ($_Project->issuetypes as $_issueType) {
925
                                        $_ProjectCreateMeta['issuetype'][$_issueType->id] = $_issueType->name;
926
                                        if (isset($_issueType->fields->security->allowedValues) && _is_array($_issueType->fields->security->allowedValues)) {
927
                                                foreach ($_issueType->fields->security->allowedValues as $_securityLevel) {
928
                                                        $_ProjectCreateMeta['security'][$_securityLevel->id] = $_securityLevel->name;
929
                                                }
930
                                        }
931
                                }
932
                                $_CreateMetaContainer[$_Project->key] = $_ProjectCreateMeta;
933
                        }
934
935
                        if (_is_array($_CreateMetaContainer)) {
936
                                $_SWIFT->Cache->Update('jiracreatemeta', $_CreateMetaContainer);
937
938
                                return $_CreateMetaContainer;
939
                        }
940
                }
941
        }
942
943
        /**
944
         * Fetches the updated Meta from the JIRA API
945
         *
946
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
947
         * @return bool 'TRUE' on success & 'FALSE' otherwise
948
         */
949
        public function GetCreateMetaByProject($_projectKey, $_issueType = '')
950
        {
951
                $_SWIFT = SWIFT::GetInstance();
952
953
                if (empty($_projectKey)) {
954
                        throw new SWIFT_Exception('Project Key: ' . $_SWIFT->Language->Get('jira_noempty'));
955
                }
956
957
                if (!$this->IsProjectValid($_projectKey)) {
958
                        throw new SWIFT_Exception('Project ' . $_projectKey . ' doesn\'t exist');
959
                }
960
961
//                $_CreateMetaCached = $_SWIFT->Cache->Get('jiracreatemeta');
962
963
//                if (!_is_array($_CreateMetaCached) || !array_key_exists($_projectKey, $_CreateMetaCached)) {
964
965
                $_queryArray = array(
966
                        'projectKeys' => $_projectKey,
967
                        'expand'      => 'projects.issuetypes.fields'
968
                );
969
970
                if (!empty($_issueType)) {
971
                        $_queryArray['issuetypeIds'] = $_issueType;
972
                }
973
974
                $_query = http_build_query($_queryArray);
975
976
                $_apiURL = $this->_url . 'rest/api/2/issue/createmeta?' . $_query;
977
978
                $this->Client->setUri($_apiURL);
979
980
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
981
982
                if ($_Response && $_Response->isSuccessful()) {
983
                        return json_decode($_Response->getBody());
984
//                                $_CreateMeta = array(
985
//                                        $_projectKey        => json_decode($_Response->getBody())
986
//                                );
987
//                                if (!$_SWIFT->Cache->Update('jiracreatemeta', $_CreateMeta))
988
//                                        return FALSE;
989
                }
990
991
                //}
992
                return $_SWIFT->Cache->Get('jiracreatemeta');
993
        }
994
995
        /**
996
         * Returns the last error
997
         *
998
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
999
         * @return string
1000
         */
1001
        public function GetErrorMessage()
1002
        {
1003
                return $this->_error;
1004
        }
1005
1006
        /**
1007
         * Sets an error message
1008
         *
1009
         * @param string $_error The error message to set
1010
         *
1011
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1012
         * @return \SWIFT_JIRABridge
1013
         */
1014
        public function SetErrorMessage($_error)
1015
        {
1016
                if (is_string($_error) && $_error != '') {
1017
                        $this->_error = $_error;
1018
1019
                        return $this;
1020
                }
1021
        }
1022
1023
        /**
1024
         * Fetches all comments by a parameter
1025
         *
1026
         * @param string $_param The parameter to filter comemnts by
1027
         * @param mixed  $_value The parameter value
1028
         *
1029
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1030
         * @return \SWIFT_JIRAComment|boolean \SWIFT_JIRAComment on success and 'FALSE' otherwise
1031
         */
1032
        public function FetchAllCommentsBy($_param = null, $_value = null)
1033
        {
1034
                if ($_param && $_value) {
1035
1036
                        if ($_param == 'issuekey') {
1037
1038
                                $_apiURL = $this->_url . 'rest/api/latest/issue/' . $_value . '/comment';
1039
1040
                                $this->Client->setUri($_apiURL);
1041
1042
                                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
1043
1044
                                if ($_Response && $_Response->isSuccessful()) {
1045
                                        $_ResponseDecoded = json_decode($_Response->getBody())->comments;
1046
1047
                                        $_CommentsContainer = array();
1048
1049
                                        foreach ($_ResponseDecoded as $_Response) {
1050
1051
                                                $_JIRAComment = new SWIFT_JIRAComment();
1052
                                                $_JIRAComment->ParseJSON($_Response);
1053
1054
                                                if ($_JIRAComment) {
1055
                                                        $_CommentsContainer[] = $_JIRAComment;
1056
                                                }
1057
                                        }
1058
1059
                                        return $_CommentsContainer;
1060
                                }
1061
1062
                                return false;
1063
                        }
1064
                }
1065
1066
                return false;
1067
        }
1068
1069
        /**
1070
         * Tests connection to JIRA
1071
         * Can/Should be used before every operation
1072
         *
1073
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1074
         * @return boolean 'TRUE' if the connection is successful, 'FALSE' otherwise
1075
         */
1076
        public function Test()
1077
        {
1078
                if (!$this->GetIsClassLoaded()) {
1079
                        throw new SWIFT_Exception(__CLASS__ . '  ' . SWIFT_CLASSNOTLOADED);
1080
                }
1081
1082
                $_SWIFT = SWIFT::GetInstance();
1083
1084
                if (!$_SWIFT->Settings->Get('bj_isenabled')) {
1085
                        return false;
1086
                }
1087
1088
                $this->Client->setUri($this->_url);
1089
1090
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
1091
1092
                if ($_Response && ($_Response->isSuccessful() || $_Response->isRedirect())) {
1093
                        return true;
1094
                }
1095
1096
                return false;
1097
        }
1098
1099
        /**
1100
         * Links a ticket with an existing JIRA issue
1101
         *
1102
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1103
         *
1104
         * @param string $_ticketID The kayako ticket id
1105
         * @param mixed  $_issueID  The JIRA issue id/key
1106
         *
1107
         * @return boolean
1108
         */
1109
        public function LinkIssue($_ticketID, $_JIRAIssueID, $_data = array())
1110
        {
1111
                if ($_JIRAIssueID && $this->IsIssueValid($_JIRAIssueID)
1112
                        && $_ticketID
1113
                ) {
1114
1115
                        $_JIRAIssueManager = $this->Get($_JIRAIssueID);
1116
1117
                        if ($_JIRAIssueManager && $_JIRAIssueManager instanceof SWIFT_JIRAIssueManager) {
1118
                                if (array_key_exists('description', $_data) && $_data['description'] != '') {
1119
1120
                                        $_JIRAComment = new SWIFT_JIRAComment();
1121
                                        $_JIRAComment->SetBody($_data['description']);
1122
                                        $_JIRAComment->SetIssue($_JIRAIssueManager);
1123
1124
                                        $this->PostComment($_JIRAComment);
1125
                                }
1126
                                //We are almost there . . . time to create a local record for Ticket <->Issue reference
1127
                                $this->Load->Library('JIRA:JIRAIssueManager', false, false, 'jira');
1128
                                $_SWIFT   = SWIFT::GetInstance();
1129
                                $_updated = $_SWIFT->Database->AutoExecute(TABLE_PREFIX . self::$_tableName, array(
1130
                                                                                                                        'ticketid' => $_SWIFT->Database->Escape($_ticketID),
1131
                                                                                                                        'issueid'  => $_SWIFT->Database->Escape($_JIRAIssueManager->GetId()),
1132
                                                                                                                        'issuekey' => $_SWIFT->Database->Escape($_JIRAIssueID)
1133
                                                                                                                        ), 'INSERT');
1134
                                if ($_updated) {
1135
                                        $_SWIFTTicketObject = SWIFT_Ticket::GetObjectOnID($_ticketID);
1136
                                        if ($_SWIFTTicketObject && $_SWIFTTicketObject instanceof SWIFT_Ticket && $_SWIFTTicketObject->GetIsClassLoaded()) {
1137
                                                $_title         = $_SWIFTTicketObject->GetTicketDisplayID();
1138
                                                $_ticketSummary = $_SWIFTTicketObject->GetProperty('subject');
1139
                                        } else {
1140
                                                $_title         = $this->Language->Get('jira_kayakoticket');
1141
                                                $_ticketSummary = '';
1142
                                        }
1143
1144
                                        $_ticketURL = SWIFT::Get('basename') . '/Tickets/Ticket/View/' . $_ticketID;
1145
1146
                                        if ($_SWIFT->Settings->Get('bj_jiraissuelinking')) {
1147
                                                $this->PostRemoteLink($_JIRAIssueID, $_ticketURL, $_title, $_ticketSummary);
1148
                                        }
1149
                                }
1150
                        } else {
1151
                                $this->SetErrorMessage($this->Language->Get('jira_noissuefound'));
1152
1153
                                return false;
1154
                        }
1155
                } else {
1156
                        $this->SetErrorMessage($this->Language->Get('jira_noissuefound'));
1157
1158
                        return false;
1159
                }
1160
1161
                return true;
1162
        }
1163
1164
        /**
1165
         * Posts a remote link to JIRA
1166
         *
1167
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1168
         *
1169
         * @param string $_issueKey  The JIRA issue key to the send to the request to
1170
         * @param string $_ticketURL Kayako ticket URL for backlinking
1171
         * @param string $_title     Remote link title
1172
         * @param string $_summary   Remote link summary
1173
         * @param int    $_status    Kayako ticket status
1174
         *
1175
         * @return bool "true" on Success, "false" otherwise
1176
         * @throws SWIFT_Exception If the Class is not Loaded
1177
         */
1178
        public function PostRemoteLink($_issueKey, $_ticketURL, $_title = '', $_summary = '', $_status = 1)
1179
        {
1180
                if (!$this->GetIsClassLoaded()) {
1181
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
1182
1183
                        return false;
1184
                }
1185
1186
                if (empty($_issueKey) || empty($_ticketURL)) {
1187
                        throw new SWIFT_Exception(SWIFT_INVALIDDATA);
1188
                }
1189
1190
                if (!$this->IsIssueValid($_issueKey)) {
1191
                        throw new SWIFT_Exception('Invalid Issue');
1192
                }
1193
                $_SWIFT = SWIFT::GetInstance();
1194
1195
                $_apiURL = $this->_url . 'rest/api/latest/issue/' . $_issueKey . '/remotelink';
1196
1197
                $this->Client->SetURI($_apiURL);
1198
1199
                $_globalID = 'system=' . $_ticketURL;
1200
1201
                $objectPayload = array(
1202
                        'url'   => $_ticketURL,
1203
                        'title' => $_title,
1204
                        'icon'  => array(
1205
                                'url16x16' => SWIFT::Get('swiftpath') . '/favicon.ico',
1206
                                'title'    => SWIFT_PRODUCT
1207
                        )
1208
                );
1209
1210
                if ($_SWIFT->Settings->Get('bj_includesubjectinlink')) {
1211
                        $objectPayload['summary'] = $_summary;
1212
                }
1213
1214
                $_ticketStatusClosed = false;
1215
                $_ticketStatusCache  = $_SWIFT->Cache->Get('statuscache');
1216
1217
                if (_is_array($_ticketStatusCache)) {
1218
                        foreach ($_SWIFT->Cache->Get('statuscache') as $_ticketStatus) {
1219
                                if ($_ticketStatus['markasresolved']) {
1220
                                        $_ticketStatusClosed = $_ticketStatus['ticketstatusid'];
1221
                                }
1222
                        }
1223
                }
1224
1225
                if ($_ticketStatusClosed && $_status == $_ticketStatusClosed) {
1226
                        $objectPayload['status'] = array(
1227
                                'resolved' => true,
1228
                                'icon'     => array(
1229
                                        'url16x16' => SWIFT::Get('swiftpath') . '__modules/jira/resources/resolved.png',
1230
                                        'title'    => $this->Language->Get('jira_ticketclosed'),
1231
                                        'link'     => $_ticketURL
1232
                                )
1233
                        );
1234
                }
1235
1236
                $this->Client->SetParameterPost('globalId', $_globalID);
1237
                $this->Client->SetParameterPost('object', $objectPayload);
1238
1239
                $_Response = $this->Client->Request(SWIFT_HTTPBase::POST, $this->_connectionTimeout);
1240
1241
                if ($_Response && $_Response->isSuccessful()) {
1242
                        return true;
1243
                }
1244
1245
                return false;
1246
        }
1247
1248
        /**
1249
         * Removes a remote issue link
1250
         *
1251
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1252
         *
1253
         * @param string   $_issueKey The JIRA issue key
1254
         * @param string | $_ticketID The Kayako ticket ID/Key
1255
         *
1256
         * @return bool "true" on Success, "false" otherwise
1257
         * @throws SWIFT_Exception If the Class is not Loaded
1258
         */
1259
        public function RemoveRemoteLink($_issueKey, $_ticketID)
1260
        {
1261
                if (!$this->GetIsClassLoaded()) {
1262
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
1263
1264
                        return false;
1265
                }
1266
1267
                $_ticketURL = SWIFT::Get('basename') . '/Tickets/Ticket/View/' . $_ticketID;
1268
1269
                $_globalID = 'system=' . $_ticketURL;
1270
1271
                $_apiURL = $this->_url . 'rest/api/latest/issue/' . $_issueKey . '/remotelink';
1272
1273
                $this->Client->SetURI($_apiURL);
1274
1275
                $this->Client->SetParameterGet('globalId', $_globalID);
1276
1277
                $_Response = $this->Client->Request(SWIFT_HTTPBase::DELETE);
1278
1279
                if ($_Response->getResponseCode() == 204) {
1280
                        return true;
1281
                } else {
1282
                        echo $_Response->getResponseCode(), ' : ', $_Response->getRawData();
1283
1284
                        return false;
1285
                }
1286
        }
1287
1288
        public function GetProjectRoles($_projectKey)
1289
        {
1290
                if (!$this->GetIsClassLoaded()) {
1291
                        throw new SWIFT_Exception(__CLASS__ . ' : ' . SWIFT_CLASSNOTLOADED);
1292
                }
1293
1294
                if (empty($_projectKey) || !is_string($_projectKey)) {
1295
                        throw new SWIFT_Exception('Project Key can not be empty');
1296
                }
1297
1298
                $_apiURL = $this->_url . 'rest/api/latest/project/' . $_projectKey . '/role';
1299
                $this->Client->SetURI($_apiURL);
1300
1301
                $_Response = $this->Client->Request(SWIFT_HTTPBase::GET, $this->_connectionTimeout);
1302
1303
                if ($_Response && $_Response->isSuccessful()) {
1304
                        $_RolesDecoded = json_decode($_Response->getBody());
1305
1306
                        return get_object_vars($_RolesDecoded);
1307
                }
1308
1309
                return false;
1310
        }
1311
1312
        /**
1313
         * Helper Function returns the ticket URL for a given interface
1314
         *
1315
         * @author Abhinav Kumar <abhinav.kumar@kayako.com>
1316
         *
1317
         * @param string $_ticketID The ticket id/key
1318
         * @param        int        The interface
1319
         *
1320
         * @return bool "true" on Success, "false" otherwise
1321
         * @throws SWIFT_Exception If the Class is not Loaded
1322
         */
1323
        public function GetTicketURL($_ticketID, $_interface = SWIFT_Interface::INTERFACE_STAFF)
1324
        {
1325
                if (!$this->GetIsClassLoaded()) {
1326
                        throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
1327
1328
                        return false;
1329
                }
1330
1331
                if ($_interface == SWIFT_Interface::INTERFACE_STAFF) {
1332
                        return SWIFT::Get('basename') . '/Tickets/Ticket/View/' . $_ticketID;
1333
                }
1334
1335
                return true;
1336
        }
1337
}